mindwire 0.1.0 → 0.1.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/dist/run.d.ts ADDED
@@ -0,0 +1,97 @@
1
+ import type { Http } from "./http.js";
2
+ import type { Event, ResultInfo, RespondInput, Run as RunData } from "./types.js";
3
+ export interface StreamOptions {
4
+ signal?: AbortSignal;
5
+ /**
6
+ * Include the daemon's `{ type: "status", meta: { stream: "open" } }` sentinel that is
7
+ * flushed the instant the stream opens (used to detect a live vs. buffered transport).
8
+ * Off by default — most consumers only care about model output.
9
+ */
10
+ includeOpenSentinel?: boolean;
11
+ }
12
+ export interface WaitResult {
13
+ run: RunData;
14
+ result?: ResultInfo;
15
+ }
16
+ /**
17
+ * A handle to one turn's run. Wraps the durable `Run` record returned by `POST /turns` and
18
+ * exposes the unified event stream, cancellation, and status polling.
19
+ *
20
+ * Stream it directly:
21
+ *
22
+ * ```ts
23
+ * const run = await mw.turn({ chatId, message: "refactor foo" });
24
+ * for await (const ev of run) {
25
+ * if (ev.type === "text") process.stdout.write(ev.text ?? "");
26
+ * }
27
+ * ```
28
+ */
29
+ export declare class Run {
30
+ private data;
31
+ private readonly http;
32
+ constructor(http: Http, data: RunData);
33
+ get id(): string;
34
+ get chatId(): string;
35
+ get agent(): string | undefined;
36
+ get status(): RunData["status"];
37
+ /** `"resolve"` on the parent of a global-resolve run; `undefined` for an ordinary turn. */
38
+ get kind(): RunData["kind"];
39
+ /** On a child iteration of a resolve run, the id of its parent resolve run; else `undefined`. */
40
+ get parentId(): string | undefined;
41
+ /** Parent of a resolve run only: why the loop ended (`"done"` | `"capped"` | `"error"` | …). */
42
+ get stopReason(): RunData["stopReason"];
43
+ /** Parent of a resolve run only: how many child turns the loop ran. */
44
+ get iterations(): number | undefined;
45
+ /** The latest known run record. */
46
+ get value(): RunData;
47
+ /** Unified SSE event stream: replay buffer, then live events, then close. */
48
+ stream(opts?: StreamOptions): AsyncGenerator<Event, void, unknown>;
49
+ /** `for await (const ev of run)` — sugar for `run.stream()`. */
50
+ [Symbol.asyncIterator](): AsyncGenerator<Event, void, unknown>;
51
+ /** Cancel the in-flight turn (kills the underlying agent process). */
52
+ cancel(): Promise<void>;
53
+ /**
54
+ * Answer a mid-turn interaction the turn is waiting on — a permission approval, or an
55
+ * AskUserQuestion / ExitPlanMode reply. Requires the agent's `respond` capability.
56
+ */
57
+ respond(input?: RespondInput): Promise<void>;
58
+ /**
59
+ * Steer a follow-up message into the running turn without cancelling it. Requires the agent's
60
+ * `input` capability.
61
+ */
62
+ sendInput(text: string): Promise<void>;
63
+ /**
64
+ * Soft-stop the running turn (ask the agent to halt current work) without the hard process kill
65
+ * {@link Run.cancel} does — the turn stays open for a follow-up via {@link Run.sendInput}.
66
+ * Requires the agent's `interrupt` capability.
67
+ */
68
+ interrupt(): Promise<void>;
69
+ /**
70
+ * Switch the model of the live turn. An empty/omitted `model` resets the turn to the agent/CLI
71
+ * default. Only meaningful on a persistent (non-bypass) turn; on a one-shot turn it is a
72
+ * best-effort no-op. Requires the agent's `setModel` capability.
73
+ */
74
+ setModel(model?: string): Promise<void>;
75
+ /**
76
+ * Switch the permission mode of the live turn (e.g. `default`, `acceptEdits`, `plan`,
77
+ * `bypassPermissions`). Only meaningful on a persistent (non-bypass) turn; on a one-shot turn it
78
+ * is a best-effort no-op. Requires the agent's `setPermissionMode` capability.
79
+ */
80
+ setPermissionMode(mode: string): Promise<void>;
81
+ /**
82
+ * `GET /runs/{id}/children` — the child iterations of a global-resolve run, oldest→newest, each as
83
+ * its own {@link Run} handle. An ordinary turn (or a resolve that ran a single iteration) returns an
84
+ * empty array. Use it to inspect the run tree a {@link Mindwire.resolve} produced.
85
+ */
86
+ children(): Promise<Run[]>;
87
+ /** Re-fetch the run record from the daemon and update this handle. */
88
+ refresh(): Promise<RunData>;
89
+ /**
90
+ * Consume the event stream to completion. Returns the final run record and the `result`
91
+ * event's summary (if any). Throws {@link RunFailedError} on an `error`/`cancelled` outcome
92
+ * unless `throwOnError` is set to `false`.
93
+ */
94
+ wait(opts?: StreamOptions & {
95
+ throwOnError?: boolean;
96
+ }): Promise<WaitResult>;
97
+ }
package/dist/sse.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * A minimal, dependency-free Server-Sent Events reader.
3
+ *
4
+ * The daemon streams `data: <json>\n\n` frames (one JSON object per event) plus `: ping`
5
+ * comment keepalives and an initial `{ "type": "status", "meta": { "stream": "open" } }`
6
+ * sentinel. This parser handles multi-line `data:` fields and `\r\n`/`\n` line endings, and
7
+ * yields the JSON-parsed payload of each event.
8
+ *
9
+ * We read via `ReadableStream.getReader()` rather than `for await` so it works on every
10
+ * runtime with WHATWG streams (Node 18+ undici, Deno, Bun, browsers), not only those that
11
+ * made the stream async-iterable.
12
+ */
13
+ export declare function readSSE<T>(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<T, void, unknown>;
@@ -0,0 +1,60 @@
1
+ import { type SandboxHost, type ExecResult, type EnsureEvent } from "./host.js";
2
+ /** What {@link provisionContainer} needs to bring up a daemon-in-a-container over a base host. */
3
+ export interface ContainerConfig {
4
+ /** Create + own a container from this image. */
5
+ image?: string;
6
+ /** Attach to an existing container (id or name) instead of creating one. */
7
+ container?: string;
8
+ /** Name for a container we create. */
9
+ name?: string;
10
+ /** Docker-on-host policy. `"never"` (default) detects and fails; `"ifMissing"` installs + starts it. */
11
+ install?: "never" | "ifMissing";
12
+ /** Extra args spliced into `docker run` (before the image), e.g. `["-e", "FOO=bar", "--gpus", "all"]`. */
13
+ createArgs?: string[];
14
+ /** Port the in-container daemon binds (published to an ephemeral loopback host port). */
15
+ daemonPort: number;
16
+ /** `AGENT_TYPE` for the in-container daemon. */
17
+ agent: string;
18
+ /** `AGENT_CWD` — working directory agents run in, inside the container. */
19
+ agentCwd: string;
20
+ /** Explicit path to a Linux `mindwired` to deploy (else resolved from the platform package). */
21
+ daemonBin?: string;
22
+ /** Redeploy when the running daemon's version differs from the SDK's bundled binary. */
23
+ autoUpdate?: boolean;
24
+ /** On `stop()`, `docker rm -f` a container we created (attached containers are left running). */
25
+ stopOnExit?: boolean;
26
+ /** Destination label carried on every {@link EnsureEvent}. Defaults to `"container"`. */
27
+ target?: string;
28
+ }
29
+ /** What {@link provisionContainer} resolves: the container it ensured and how to reach + tear it down. */
30
+ export interface ContainerHandle {
31
+ /** The full container id (created) or the id/name we attached to. */
32
+ containerId: string;
33
+ /** The ephemeral host port the in-container daemon is published to, on the base machine's loopback. */
34
+ hostPort: number;
35
+ /** Tear down: `docker rm -f` the container if we created it and `stopOnExit` is set. Idempotent. */
36
+ stop(): Promise<void>;
37
+ }
38
+ /**
39
+ * Ensure Docker on the base host, bring up a container, and deploy `mindwired` inside it. Decoupled and
40
+ * injectable (like `provisionSsh`/`provisionDocker`): tests drive it with a fake {@link SandboxHost}.
41
+ * The `install`/`provision` phases stream through `onLog`; the daemon cycle then streams its own phases.
42
+ */
43
+ export declare function provisionContainer(host: SandboxHost, cfg: ContainerConfig, onLog?: (e: EnsureEvent) => void): Promise<ContainerHandle>;
44
+ /**
45
+ * Wraps a base {@link SandboxHost} so every command runs *inside* a container and every file lands
46
+ * inside it — nothing more than `docker exec` / `docker cp` layered on the base's own `exec`/`putFile`.
47
+ * This is the crux of the reuse: the shared {@link ensureDaemon} cycle sees an ordinary `SandboxHost`
48
+ * and never learns there's a container (or an SSH hop) underneath.
49
+ */
50
+ export declare class ContainerHost implements SandboxHost {
51
+ private readonly base;
52
+ private readonly containerId;
53
+ constructor(base: SandboxHost, containerId: string);
54
+ exec(argv: string[], opts?: {
55
+ timeoutSeconds?: number;
56
+ }): Promise<ExecResult>;
57
+ putFile(path: string, data: Uint8Array, opts?: {
58
+ mode?: string;
59
+ }): Promise<void>;
60
+ }
@@ -0,0 +1,114 @@
1
+ import { type EnsureEvent } from "./host.js";
2
+ import type { Target, TargetHandle } from "./index.js";
3
+ /**
4
+ * How to reach the Docker **engine**. Passed straight to `new Docker(engine)` (the `dockerode`
5
+ * constructor) — a local socket or a TCP/TLS endpoint. Nested (not flattened) so its `port` (the
6
+ * engine's TCP port) never collides with {@link DockerConfig.port} (the in-container daemon's port).
7
+ * Omit it entirely for the ambient local engine.
8
+ *
9
+ * To reach a **remote host over SSH**, prefer `ssh({ docker })` — mindwire's exec-based container layer
10
+ * that needs only SSH credentials (no engine socket forwarding, no extra deps) — rather than routing
11
+ * `dockerode` over SSH here.
12
+ */
13
+ export interface DockerEngineOptions {
14
+ /** Remote engine host (TCP). */
15
+ host?: string;
16
+ /** Engine TCP port (e.g. 2375 / 2376). */
17
+ port?: number;
18
+ /** Local engine socket path (e.g. `/var/run/docker.sock`). */
19
+ socketPath?: string;
20
+ /** Transport to the engine. */
21
+ protocol?: "http" | "https";
22
+ /** TLS material for a `https` engine. */
23
+ ca?: string | Buffer;
24
+ /** TLS material for a `https` engine. */
25
+ cert?: string | Buffer;
26
+ /** TLS material for a `https` engine. */
27
+ key?: string | Buffer;
28
+ }
29
+ /**
30
+ * Config for the Docker target. Supply `image` to create+own a container, or `container` to attach to
31
+ * an existing one (which must already publish `port`). Point at a remote engine with `engine` (or pass
32
+ * your own `docker` instance). `agent` falls back to the client's default agent.
33
+ */
34
+ export interface DockerConfig {
35
+ /** A `dockerode` instance to use. Takes precedence over `engine`. Defaults to `new Docker(engine)`. */
36
+ docker?: DockerodeLike;
37
+ /** How to reach the Docker engine (remote host / socket / TLS). Ignored when `docker` is passed. */
38
+ engine?: DockerEngineOptions;
39
+ /** Create + own a container from this image. */
40
+ image?: string;
41
+ /** Attach to an existing container (id or name) instead of creating one. */
42
+ container?: string;
43
+ /** Extra options merged into `createContainer` (native dockerode/Docker API fields). */
44
+ createOptions?: Record<string, unknown>;
45
+ /** Port the in-container daemon binds (published to an ephemeral host port). */
46
+ port?: number;
47
+ /** `AGENT_TYPE` for the in-container daemon. Defaults to the client's agent, then `claude-code`. */
48
+ agent?: string;
49
+ /** `AGENT_CWD` — working directory agents run in, inside the container. */
50
+ agentCwd?: string;
51
+ /** Explicit path to a Linux `mindwired` to deploy (else resolved from the platform package). */
52
+ daemonBin?: string;
53
+ /** Redeploy when the running daemon's version differs from the SDK's bundled binary. */
54
+ autoUpdate?: boolean;
55
+ /** On `close()`, stop + remove a container we created (attached containers are left running). */
56
+ stopOnExit?: boolean;
57
+ }
58
+ /**
59
+ * The Docker target. Returns a {@link Target} whose `connect()` creates (or attaches to) a container,
60
+ * ensures `mindwired` runs inside it, and points the SDK at the published port.
61
+ *
62
+ * ```ts
63
+ * new Mindwire({ agent: "claude-code", target: docker({ image: "my/agent-image" }) });
64
+ * new Mindwire({ agent: "claude-code", target: docker({ container: "my-running-box" }) });
65
+ * new Mindwire({ agent: "claude-code", target: docker({ image: "x", engine: { host: "10.0.0.5", port: 2375 } }) });
66
+ * ```
67
+ */
68
+ export declare function docker(config?: DockerConfig): Target;
69
+ interface DuplexLike {
70
+ on(event: string, listener: (...args: unknown[]) => void): DuplexLike;
71
+ }
72
+ interface ExecLike {
73
+ start(opts: Record<string, unknown>): Promise<DuplexLike>;
74
+ inspect(): Promise<{
75
+ ExitCode?: number;
76
+ Running?: boolean;
77
+ }>;
78
+ }
79
+ interface ContainerInspect {
80
+ State?: {
81
+ Running?: boolean;
82
+ };
83
+ NetworkSettings?: {
84
+ Ports?: Record<string, Array<{
85
+ HostIp?: string;
86
+ HostPort?: string;
87
+ }> | null>;
88
+ };
89
+ }
90
+ interface ContainerLike {
91
+ readonly id: string;
92
+ start(): Promise<unknown>;
93
+ stop(): Promise<unknown>;
94
+ remove(opts?: Record<string, unknown>): Promise<unknown>;
95
+ inspect(): Promise<ContainerInspect>;
96
+ exec(opts: Record<string, unknown>): Promise<ExecLike>;
97
+ putArchive(file: Uint8Array, opts: {
98
+ path: string;
99
+ }): Promise<unknown>;
100
+ modem: {
101
+ demuxStream(stream: DuplexLike, stdout: unknown, stderr: unknown): void;
102
+ };
103
+ }
104
+ export interface DockerodeLike {
105
+ getContainer(id: string): ContainerLike;
106
+ createContainer(opts: Record<string, unknown>): Promise<ContainerLike>;
107
+ }
108
+ /**
109
+ * The provisioning flow, decoupled from the `dockerode` import so it can be driven by an injected fake
110
+ * in tests. Creates (or attaches to) a container, resolves its published host port, ensures the
111
+ * daemon, and returns a handle pointed at `http://127.0.0.1:<hostPort>`.
112
+ */
113
+ export declare function provisionDocker(docker: DockerodeLike, config?: DockerConfig, onLog?: (e: EnsureEvent) => void): Promise<TargetHandle>;
114
+ export {};
@@ -0,0 +1,81 @@
1
+ /** Result of running a command in a sandbox — normalized (camelCase) across backends. */
2
+ export interface ExecResult {
3
+ exitCode?: number;
4
+ stdout?: string;
5
+ stderr?: string;
6
+ error?: string;
7
+ }
8
+ /**
9
+ * The minimal surface an adapter exposes so the shared {@link ensureDaemon} cycle can drive any
10
+ * backend. Two primitives only — running a command to completion, and landing raw bytes at a path.
11
+ * How they're implemented (Oblien's runtime exec + base64 files API, Docker's exec + tar putArchive,
12
+ * …) is the adapter's business; the cycle never sees it.
13
+ */
14
+ export interface SandboxHost {
15
+ /** Run a command to completion (foreground) inside the sandbox and return its buffered result. */
16
+ exec(argv: string[], opts?: {
17
+ timeoutSeconds?: number;
18
+ }): Promise<ExecResult>;
19
+ /** Land raw bytes at an absolute path inside the sandbox (made executable via `opts.mode`). */
20
+ putFile(path: string, data: Uint8Array, opts?: {
21
+ mode?: string;
22
+ }): Promise<void>;
23
+ }
24
+ /** What {@link ensureDaemon} needs: the daemon knobs plus the reconcile inputs. */
25
+ export interface EnsureDaemonConfig {
26
+ /** Port the in-sandbox daemon binds (on `0.0.0.0`, so a published port can route in). */
27
+ port: number;
28
+ /** `AGENT_TYPE` for the in-sandbox daemon. */
29
+ agent: string;
30
+ /** `AGENT_CWD` — working directory agents run in, inside the sandbox. */
31
+ agentCwd: string;
32
+ /** Explicit path to a Linux `mindwired` to deploy (else resolved from the platform package). */
33
+ daemonBin?: string;
34
+ /** Redeploy when the running daemon's version differs from `desiredVersion`. Off by default. */
35
+ autoUpdate?: boolean;
36
+ /** Version to reconcile against. Defaults to {@link SDK_VERSION} (the bundled binary's version). */
37
+ desiredVersion?: string;
38
+ /** Destination label carried on every {@link EnsureEvent} (e.g. `"ssh"`/`"docker"`/`"oblien"`). */
39
+ target?: string;
40
+ /** Receives a step {@link EnsureEvent} at each phase. A throwing callback can't abort provisioning. */
41
+ onLog?: (e: EnsureEvent) => void;
42
+ }
43
+ /**
44
+ * A progress event emitted at each phase of the ensure cycle (and, one-shot, by the `local`/`remote`
45
+ * targets). Surfaced to the caller through the client `logger` callback; the same steps `mw.ensure()`
46
+ * awaits. Normal order: `connect` (runtime reachable) → `probe` (health checked) → either `skip`
47
+ * (a healthy current daemon is kept) or `upload` → `launch` → `ready` (a daemon is deployed). `error`
48
+ * is emitted if any phase throws.
49
+ *
50
+ * Two extra phases prefix the cycle when a container is provisioned first (e.g. `ssh({ docker })`):
51
+ * `install` (Docker on the host detected — and, opt-in, installed/started) and `provision` (the
52
+ * container created/started and its published port resolved). Those are emitted by the container layer
53
+ * before it hands the in-container host to the ensure cycle, so the full order is
54
+ * `connect → install → provision → probe → (skip | upload → launch → ready)`.
55
+ */
56
+ export interface EnsureEvent {
57
+ phase: "connect" | "install" | "provision" | "probe" | "download" | "upload" | "launch" | "ready" | "skip" | "error";
58
+ /** Destination label, e.g. `"ssh"` / `"docker"` / `"oblien"` / `"local"` / `"remote"`. */
59
+ target: string;
60
+ /** Human-readable one-line status. */
61
+ message: string;
62
+ /** The daemon's reported version, when known (on `probe` / `skip`). */
63
+ version?: string;
64
+ /** Target architecture the daemon was resolved for (on `upload`). */
65
+ arch?: "amd64" | "arm64";
66
+ /** Size of the uploaded daemon binary in bytes (on `upload`). */
67
+ bytes?: number;
68
+ /** Error message (on `error`). */
69
+ error?: string;
70
+ }
71
+ /**
72
+ * Make sure a healthy `mindwired` of the desired version is reachable at `127.0.0.1:<port>` inside the
73
+ * sandbox, deploying it if absent (or redeploying if stale and `autoUpdate` is set). Idempotent: a
74
+ * healthy, current daemon (e.g. an image that autostarts it, or a reused sandbox) is a no-op.
75
+ */
76
+ export declare function ensureDaemon(host: SandboxHost, cfg: EnsureDaemonConfig): Promise<void>;
77
+ /**
78
+ * Resolve a Linux `mindwired` on the host running the SDK: an explicit `daemonBin`, else download the
79
+ * SDK-matched release binary, verify its checksum, and return its local cache path for upload.
80
+ */
81
+ export declare function resolveLinuxDaemon(explicit: string | undefined, arch: "amd64" | "arm64"): Promise<string>;
@@ -0,0 +1,76 @@
1
+ import type { FetchLike, TokenGetter } from "../http.js";
2
+ import { type EmbeddedOptions } from "../embedded.js";
3
+ import type { EnsureEvent } from "./host.js";
4
+ /**
5
+ * What `connect()` is told about the turn's context. Provisioning knobs (image, port, credentials, …)
6
+ * live on each factory's own config — this is only the client-level context every target shares.
7
+ */
8
+ export interface ConnectSpec {
9
+ /** The client's default agent, used as the in-daemon `AGENT_TYPE` when the target provisions one. */
10
+ agent?: string;
11
+ /** Receives an {@link EnsureEvent} at each provisioning phase (wired from the client `logger`). */
12
+ onLog?: (e: EnsureEvent) => void;
13
+ }
14
+ /**
15
+ * A live transport descriptor a target returns from {@link Target.connect} — everything the SDK's
16
+ * `Http` layer needs to reach the daemon at this destination.
17
+ */
18
+ export interface TargetHandle {
19
+ /** Stable id of the destination this handle drives (for logging / reuse). */
20
+ id: string;
21
+ /** Base URL for the daemon. With a custom `fetch`, this may be a sentinel the fetch strips. */
22
+ baseUrl: string;
23
+ /**
24
+ * A transport-specific `fetch` for this destination — used for both unary requests and SSE streams.
25
+ * A target supplies it to route every call through its runtime (e.g. Oblien's `rt.proxy`); a
26
+ * direct-HTTP destination (loopback, a published Docker port, an SSH tunnel) omits it and the
27
+ * client's default fetch is used.
28
+ */
29
+ fetch?: FetchLike;
30
+ /** Per-request headers this transport must send (e.g. a proxy-target port). */
31
+ headers?: Record<string, string>;
32
+ /** A static bearer token, if the destination uses one. */
33
+ token?: string;
34
+ /** Fetch the current bearer for a rotating credential; re-mints on `{force:true}`. */
35
+ getToken?: TokenGetter;
36
+ /** Release destination-owned resources (per the factory's `stopOnExit`). Idempotent. */
37
+ stop(): Promise<void>;
38
+ }
39
+ /**
40
+ * A destination for the mindwire daemon. Given a {@link ConnectSpec}, provision (or reuse) the
41
+ * environment, ensure a reachable daemon, and return a {@link TargetHandle}. The built-ins are
42
+ * {@link local} / {@link remote} (here) and {@link import("./ssh.js").ssh} /
43
+ * {@link import("./docker.js").docker} / {@link import("./oblien.js").oblien}; a custom backend is
44
+ * just another object with this shape.
45
+ */
46
+ export interface Target {
47
+ /** Destination id, e.g. `"local"` / `"remote"` / `"ssh"` / `"docker"` / `"oblien"`. */
48
+ readonly name: string;
49
+ connect(spec: ConnectSpec): Promise<TargetHandle>;
50
+ }
51
+ /**
52
+ * The default destination: an **embedded** daemon on loopback. On a server runtime (Node/Bun/Deno)
53
+ * `connect()` auto-spawns the bundled `mindwired` on a free `127.0.0.1` port and points the SDK at it,
54
+ * so `new Mindwire()` "just works" with nothing to deploy.
55
+ *
56
+ * Embedded daemons are memoized by config (see embedded.ts): two zero-config `local()` clients share
57
+ * one loopback daemon (one environment), while `local({ cwd })` / `local({ statePath })` isolate into
58
+ * their own. `stop()` is a **no-op** — the shared daemon is reaped on process exit (Risk 5).
59
+ */
60
+ export declare function local(opts?: EmbeddedOptions): Target;
61
+ /** Options for {@link remote}. */
62
+ export interface RemoteOptions {
63
+ /** Bearer token for the daemon, if it requires one. */
64
+ token?: string;
65
+ /** Extra headers merged into every request. */
66
+ headers?: Record<string, string>;
67
+ /** Custom fetch for this destination (else the client default / global fetch). */
68
+ fetch?: FetchLike;
69
+ }
70
+ /**
71
+ * A **remote** daemon you already run, reached over plain HTTP at `baseUrl`. `connect()` returns the
72
+ * transport immediately without a network round-trip — there is no ensure/probe here; `mw.health()`
73
+ * is the real liveness check (Risk 6). Required in the browser / edge runtimes, where a daemon can't
74
+ * be spawned. `stop()` is a no-op (mindwire doesn't own a daemon it didn't start).
75
+ */
76
+ export declare function remote(baseUrl: string, opts?: RemoteOptions): Target;
@@ -0,0 +1,112 @@
1
+ import { type EnsureEvent } from "./host.js";
2
+ import type { Target, TargetHandle } from "./index.js";
3
+ /**
4
+ * Config for the Oblien target — auth + endpoint plus the workspace/daemon provisioning knobs. Only
5
+ * `clientId`/`clientSecret`/`baseUrl` are about reaching Oblien; everything else describes the
6
+ * workspace to provision and the daemon to run in it. Credentials fall back to the environment (see
7
+ * {@link connectOblien}); the daemon's `agent` falls back to the client's default agent.
8
+ */
9
+ export interface OblienConfig {
10
+ /** Sandbox client id. Falls back to `MINDWIRE_SANDBOX_CLIENT_ID`, then `OBLIEN_CLIENT_ID`. */
11
+ clientId?: string;
12
+ /** Sandbox client secret. Falls back to `MINDWIRE_SANDBOX_CLIENT_SECRET`, then `OBLIEN_CLIENT_SECRET`. */
13
+ clientSecret?: string;
14
+ /** Management-API base. Defaults to the `oblien` SDK default. */
15
+ baseUrl?: string;
16
+ /** `AGENT_TYPE` for the in-workspace daemon. Defaults to the client's agent, then `claude-code`. */
17
+ agent?: string;
18
+ /** `AGENT_CWD` — working directory agents run in, inside the workspace. */
19
+ agentCwd?: string;
20
+ /** Loopback port the in-workspace daemon listens on. */
21
+ port?: number;
22
+ /** Explicit path to a Linux `mindwired` to deploy (else resolved from the platform package). */
23
+ daemonBin?: string;
24
+ /** Redeploy the daemon when the running version differs from the SDK's bundled binary. Off by default. */
25
+ autoUpdate?: boolean;
26
+ /** On `close()`, tear the workspace down (delete one we created / stop one we reused). */
27
+ stopOnExit?: boolean;
28
+ /** Image for a new workspace. Ideally one that already runs `mindwired` and ships the target agent CLI. */
29
+ image?: string;
30
+ /** Name for a new workspace. */
31
+ name?: string;
32
+ /** Reuse an existing workspace instead of creating one (skips the cold-start provision). */
33
+ workspaceId?: string;
34
+ /** vCPUs for a new workspace. */
35
+ cpus?: number;
36
+ /** Memory (MB) for a new workspace. */
37
+ memoryMb?: number;
38
+ /** Disk (MB) for a new workspace. */
39
+ diskMb?: number;
40
+ /** Lifecycle: `temporary` (auto-reaped) or `permanent`. */
41
+ mode?: "temporary" | "permanent";
42
+ }
43
+ /**
44
+ * The Oblien target. Returns a {@link Target} whose `connect()` provisions (or reuses) an Oblien
45
+ * workspace, ensures `mindwired` runs inside it, and points the SDK at the runtime proxy. The
46
+ * `oblien` npm peer is only touched inside `connect()`.
47
+ *
48
+ * ```ts
49
+ * new Mindwire({ agent: "claude-code", target: oblien({ clientId, clientSecret }) });
50
+ * ```
51
+ */
52
+ export declare function oblien(config?: OblienConfig): Target;
53
+ interface OblienExecResult {
54
+ exit_code?: number;
55
+ stdout?: string;
56
+ stderr?: string;
57
+ error?: string;
58
+ status?: string;
59
+ }
60
+ interface OblienExecParams {
61
+ execMode?: "auto" | "shell" | "direct";
62
+ timeoutSeconds?: number;
63
+ keepLogs?: boolean;
64
+ }
65
+ interface RuntimeProxyLike {
66
+ /** Reverse-proxy a request to `127.0.0.1:<port>` inside the workspace. SSE/streaming passes through. */
67
+ fetch(input: string, init?: RequestInit): Promise<Response>;
68
+ }
69
+ interface RuntimeLike {
70
+ exec: {
71
+ run(cmd: string[], params?: OblienExecParams): Promise<OblienExecResult>;
72
+ };
73
+ files: {
74
+ write(params: {
75
+ fullPath: string;
76
+ content: string;
77
+ createDirs?: boolean;
78
+ append?: boolean;
79
+ mode?: string;
80
+ }): Promise<unknown>;
81
+ };
82
+ proxy(port: number, host?: string): RuntimeProxyLike;
83
+ }
84
+ interface WorkspaceHandleLike {
85
+ id: string;
86
+ start(params?: {
87
+ force?: boolean;
88
+ }): Promise<unknown>;
89
+ stop(): Promise<unknown>;
90
+ delete(): Promise<unknown>;
91
+ runtime(options?: {
92
+ force?: boolean;
93
+ }): Promise<RuntimeLike>;
94
+ }
95
+ interface OblienClientLike {
96
+ workspaces: {
97
+ create(params: Record<string, unknown>): Promise<{
98
+ id: string;
99
+ }>;
100
+ };
101
+ workspace(id: string): WorkspaceHandleLike;
102
+ }
103
+ /**
104
+ * The provisioning flow, decoupled from the `oblien` import so it can be driven by an injected client
105
+ * (used by the unit tests, and available for advanced embedding). Provisions/reuses a workspace,
106
+ * ensures the daemon, and returns a handle whose `fetch` routes every request through the runtime
107
+ * proxy (re-acquiring the runtime and retrying once on a `401`).
108
+ */
109
+ export declare function provisionOblien(client: OblienClientLike, config?: OblienConfig, onLog?: (e: EnsureEvent) => void): Promise<TargetHandle & {
110
+ workspaceId: string;
111
+ }>;
112
+ export {};