@amends-dev/harness-opencode 0.0.0-stage → 0.2.0

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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/Opencode2Agent.d.ts +105 -0
  3. package/Opencode2Agent.d.ts.map +1 -0
  4. package/Opencode2Agent.js +72 -0
  5. package/Opencode2Agent.js.map +1 -0
  6. package/OpencodeAgent.d.ts +110 -0
  7. package/OpencodeAgent.d.ts.map +1 -0
  8. package/OpencodeAgent.js +83 -0
  9. package/OpencodeAgent.js.map +1 -0
  10. package/README.md +223 -2
  11. package/index.d.ts +18 -0
  12. package/index.d.ts.map +1 -0
  13. package/index.js +19 -0
  14. package/index.js.map +1 -0
  15. package/internal/agent.d.ts +29 -0
  16. package/internal/agent.d.ts.map +1 -0
  17. package/internal/agent.js +34 -0
  18. package/internal/agent.js.map +1 -0
  19. package/internal/bridge/bunBridge.d.ts +33 -0
  20. package/internal/bridge/bunBridge.d.ts.map +1 -0
  21. package/internal/bridge/bunBridge.js +62 -0
  22. package/internal/bridge/bunBridge.js.map +1 -0
  23. package/internal/bridge/driver.d.ts +81 -0
  24. package/internal/bridge/driver.d.ts.map +1 -0
  25. package/internal/bridge/driver.js +82 -0
  26. package/internal/bridge/driver.js.map +1 -0
  27. package/internal/bridge/hostTools.d.ts +28 -0
  28. package/internal/bridge/hostTools.d.ts.map +1 -0
  29. package/internal/bridge/hostTools.js +41 -0
  30. package/internal/bridge/hostTools.js.map +1 -0
  31. package/internal/bridge/server.d.ts +64 -0
  32. package/internal/bridge/server.d.ts.map +1 -0
  33. package/internal/bridge/server.js +129 -0
  34. package/internal/bridge/server.js.map +1 -0
  35. package/internal/bridge/steps.d.ts +29 -0
  36. package/internal/bridge/steps.d.ts.map +1 -0
  37. package/internal/bridge/steps.js +42 -0
  38. package/internal/bridge/steps.js.map +1 -0
  39. package/internal/bridge/v1/api.d.ts +181 -0
  40. package/internal/bridge/v1/api.d.ts.map +1 -0
  41. package/internal/bridge/v1/api.js +83 -0
  42. package/internal/bridge/v1/api.js.map +1 -0
  43. package/internal/bridge/v1/event.d.ts +597 -0
  44. package/internal/bridge/v1/event.d.ts.map +1 -0
  45. package/internal/bridge/v1/event.js +186 -0
  46. package/internal/bridge/v1/event.js.map +1 -0
  47. package/internal/bridge/v1/main.d.ts +6 -0
  48. package/internal/bridge/v1/main.d.ts.map +1 -0
  49. package/internal/bridge/v1/main.js +8 -0
  50. package/internal/bridge/v1/main.js.map +1 -0
  51. package/internal/bridge/v1/prompt.d.ts +18 -0
  52. package/internal/bridge/v1/prompt.d.ts.map +1 -0
  53. package/internal/bridge/v1/prompt.js +92 -0
  54. package/internal/bridge/v1/prompt.js.map +1 -0
  55. package/internal/bridge/v1/session.d.ts +28 -0
  56. package/internal/bridge/v1/session.d.ts.map +1 -0
  57. package/internal/bridge/v1/session.js +188 -0
  58. package/internal/bridge/v1/session.js.map +1 -0
  59. package/internal/bridge/v1/turn.d.ts +82 -0
  60. package/internal/bridge/v1/turn.d.ts.map +1 -0
  61. package/internal/bridge/v1/turn.js +335 -0
  62. package/internal/bridge/v1/turn.js.map +1 -0
  63. package/internal/bridge/v2/api.d.ts +86 -0
  64. package/internal/bridge/v2/api.d.ts.map +1 -0
  65. package/internal/bridge/v2/api.js +105 -0
  66. package/internal/bridge/v2/api.js.map +1 -0
  67. package/internal/bridge/v2/event.d.ts +539 -0
  68. package/internal/bridge/v2/event.d.ts.map +1 -0
  69. package/internal/bridge/v2/event.js +164 -0
  70. package/internal/bridge/v2/event.js.map +1 -0
  71. package/internal/bridge/v2/main.d.ts +6 -0
  72. package/internal/bridge/v2/main.d.ts.map +1 -0
  73. package/internal/bridge/v2/main.js +8 -0
  74. package/internal/bridge/v2/main.js.map +1 -0
  75. package/internal/bridge/v2/prompt.d.ts +109 -0
  76. package/internal/bridge/v2/prompt.d.ts.map +1 -0
  77. package/internal/bridge/v2/prompt.js +209 -0
  78. package/internal/bridge/v2/prompt.js.map +1 -0
  79. package/internal/bridge/v2/session.d.ts +21 -0
  80. package/internal/bridge/v2/session.d.ts.map +1 -0
  81. package/internal/bridge/v2/session.js +198 -0
  82. package/internal/bridge/v2/session.js.map +1 -0
  83. package/internal/bridge/v2/turn.d.ts +62 -0
  84. package/internal/bridge/v2/turn.d.ts.map +1 -0
  85. package/internal/bridge/v2/turn.js +277 -0
  86. package/internal/bridge/v2/turn.js.map +1 -0
  87. package/internal/models.d.ts +47 -0
  88. package/internal/models.d.ts.map +1 -0
  89. package/internal/models.js +170 -0
  90. package/internal/models.js.map +1 -0
  91. package/internal/template.d.ts +46 -0
  92. package/internal/template.d.ts.map +1 -0
  93. package/internal/template.js +267 -0
  94. package/internal/template.js.map +1 -0
  95. package/package.json +39 -4
package/index.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * opencode as an agent for the `@amends-dev/harness` contract, working in a sandbox behind its
3
+ * bridge, which the agent's template installs there with opencode itself. opencode has two
4
+ * versions, each with a session API of its own, and the package an agent for each: `OpencodeAgent`
5
+ * runs opencode 1, which takes everything a turn gives, and `Opencode2Agent` runs opencode 2, which
6
+ * records a session started on another agent as its own but does not answer in JSON yet.
7
+ *
8
+ * @since 0.1.0
9
+ */
10
+ /**
11
+ * @since 0.1.0
12
+ */
13
+ export * as Opencode2Agent from "./Opencode2Agent.ts";
14
+ /**
15
+ * @since 0.1.0
16
+ */
17
+ export * as OpencodeAgent from "./OpencodeAgent.ts";
18
+ //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;GAEG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AAErD;;GAEG;AACH,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA"}
package/index.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * opencode as an agent for the `@amends-dev/harness` contract, working in a sandbox behind its
3
+ * bridge, which the agent's template installs there with opencode itself. opencode has two
4
+ * versions, each with a session API of its own, and the package an agent for each: `OpencodeAgent`
5
+ * runs opencode 1, which takes everything a turn gives, and `Opencode2Agent` runs opencode 2, which
6
+ * records a session started on another agent as its own but does not answer in JSON yet.
7
+ *
8
+ * @since 0.1.0
9
+ */
10
+ // @barrel: Auto-generated exports. Do not edit manually.
11
+ /**
12
+ * @since 0.1.0
13
+ */
14
+ export * as Opencode2Agent from "./Opencode2Agent.js";
15
+ /**
16
+ * @since 0.1.0
17
+ */
18
+ export * as OpencodeAgent from "./OpencodeAgent.js";
19
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,yDAAyD;AAEzD;;GAEG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AAErD;;GAEG;AACH,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * What `OpencodeAgent` and `Opencode2Agent` make: the agent over one version of opencode, whose
3
+ * sessions reach it through the bridge its installation launches in each sandbox.
4
+ */
5
+ import { type Agent, HarnessError } from "@amends-dev/harness";
6
+ import type { Sandbox } from "@amends-dev/sandbox";
7
+ import type * as Crypto from "effect/Crypto";
8
+ import * as Effect from "effect/Effect";
9
+ import type * as Redacted from "effect/Redacted";
10
+ import type * as Schema from "effect/Schema";
11
+ import type * as Socket from "effect/socket/Socket";
12
+ import { type Version } from "./template.ts";
13
+ /** What each version's agent is made with, as its module documents. */
14
+ export interface Options extends Agent.Options {
15
+ readonly token: (id: Sandbox.SandboxId) => Redacted.Redacted<string>;
16
+ readonly config?: {
17
+ readonly [key: string]: Schema.Json;
18
+ };
19
+ readonly env?: Readonly<Record<string, string>>;
20
+ }
21
+ /** Which opencode an agent runs, the id hosts know it by, and how long its tools' names may be. */
22
+ export interface Kind {
23
+ readonly id: string;
24
+ readonly version: Version;
25
+ readonly maxToolNameLength?: number;
26
+ }
27
+ /** The agent of `kind`, made with `options`. */
28
+ export declare const make: (kind: Kind, options: Options) => Effect.Effect<Agent.Agent, HarnessError.HarnessError | import("effect/PlatformError").PlatformError, Crypto.Crypto | Socket.WebSocketConstructor>;
29
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/internal/agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,KAAK,KAAK,EAAgB,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAC5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAC5C,OAAO,KAAK,KAAK,MAAM,MAAM,sBAAsB,CAAA;AAGnD,OAAO,EAAoB,KAAK,OAAO,EAAE,MAAM,eAAe,CAAA;AAE9D,uEAAuE;AACvE,MAAM,WAAW,OAAQ,SAAQ,KAAK,CAAC,OAAO;IAC5C,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAA;KAAE,CAAA;IACzD,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAChD;AAED,mGAAmG;AACnG,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CACpC;AAED,gDAAgD;AAChD,eAAO,MAAM,IAAI,qLAyBf,CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * What `OpencodeAgent` and `Opencode2Agent` make: the agent over one version of opencode, whose
3
+ * sessions reach it through the bridge its installation launches in each sandbox.
4
+ */
5
+ import { BridgeClient, HarnessError } from "@amends-dev/harness";
6
+ import * as Effect from "effect/Effect";
7
+ import { modelsOf } from "./models.js";
8
+ import { makeInstallation } from "./template.js";
9
+ /** The agent of `kind`, made with `options`. */
10
+ export const make = Effect.fnUntraced(function* (kind, options) {
11
+ const models = yield* Effect.fromResult(modelsOf(kind.version, options)).pipe(Effect.mapError((reason) => new HarnessError.HarnessError({ agent: kind.id, reason })));
12
+ const installation = yield* makeInstallation(kind.version);
13
+ const services = yield* Effect.context();
14
+ const bridge = {
15
+ id: kind.id,
16
+ ...installation,
17
+ token: options.token,
18
+ agentOptions: {
19
+ model: models.model,
20
+ models: models.models,
21
+ config: { ...options.config, ...models.config },
22
+ env: { ...options.env, ...models.env }
23
+ }
24
+ };
25
+ const agent = {
26
+ id: kind.id,
27
+ requiresSandbox: true,
28
+ template: installation.template,
29
+ ...(kind.maxToolNameLength !== undefined && { maxToolNameLength: kind.maxToolNameLength }),
30
+ createSession: (sessionOptions) => Effect.provide(BridgeClient.createSession(bridge, sessionOptions), services)
31
+ };
32
+ return agent;
33
+ });
34
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/internal/agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAc,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAG5E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAKvC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAgB,MAAM,eAAe,CAAA;AAgB9D,gDAAgD;AAChD,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,IAAU,EAAE,OAAgB;IAC3E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAC3E,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CACvF,CAAA;IACD,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC1D,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAA+C,CAAA;IACrF,MAAM,MAAM,GAAyB;QACnC,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,GAAG,YAAY;QACf,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,YAAY,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;YAC/C,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,GAAG,EAAE;SACf;KAC1B,CAAA;IACD,MAAM,KAAK,GAAgB;QACzB,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,eAAe,EAAE,IAAI;QACrB,QAAQ,EAAE,YAAY,CAAC,QAAQ;QAC/B,GAAG,CAAC,IAAI,CAAC,iBAAiB,KAAK,SAAS,IAAI,EAAE,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC1F,aAAa,EAAE,CAAC,cAAc,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,QAAQ,CAAC;KAChH,CAAA;IACD,OAAO,KAAK,CAAA;AACd,CAAC,CAAC,CAAA"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Runs a bridge program from Bun: `runProgram` makes opencode's driver from the launch options a
3
+ * host gave, and `serve` serves it on every interface of the sandbox, at a port the sandbox picks,
4
+ * until the bridge exits idle or another takes its place.
5
+ *
6
+ * Bun's server never finishes stopping once a WebSocket has been open, so it runs in a scope of its
7
+ * own, which the bridge gives a second to close after the bridge's own finalizers have run, rather
8
+ * than wait for hosts to close their connections.
9
+ */
10
+ import { type Bridge, BridgeServer, HostToolRelay } from "@amends-dev/harness";
11
+ import * as Effect from "effect/Effect";
12
+ import * as Schema from "effect/Schema";
13
+ import * as Scope from "effect/Scope";
14
+ import * as Driver from "./driver.ts";
15
+ /**
16
+ * Runs the bridge program of the agent `agent`, which a host launches in its sandbox. It reads the
17
+ * launch options the host gave it on standard input, makes opencode's driver from the agent options
18
+ * among them, with the sessions `makeCreateSession` creates, and serves the driver to hosts until
19
+ * it exits idle or another bridge takes its place. opencode's server exiting by itself ends it too,
20
+ * for the next host to launch both again.
21
+ *
22
+ * Beside the bridge it serves the `HostToolRelay`, through which opencode calls the host's tools,
23
+ * on 127.0.0.1 only, where opencode's server reaches it. The driver runs the opencode in
24
+ * `directory`, where the template installs it beside the program, unless the agent options name
25
+ * another command.
26
+ */
27
+ export declare const runProgram: (agent: string, directory: string, makeCreateSession: (relay: HostToolRelay.HostToolRelay["Service"]) => Driver.CreateSession) => void;
28
+ /**
29
+ * Serves `driver` to hosts as `launch` says, until the bridge exits idle, after `idleTimeout`, or
30
+ * another takes its place.
31
+ */
32
+ export declare const serve: (driver: Bridge.Driver, launch: Bridge.LaunchOptions, options?: Pick<BridgeServer.Options, "idleTimeout"> | undefined) => Effect.Effect<undefined, import("effect/PlatformError").PlatformError | Schema.SchemaError | import("effect/http/HttpServerError").ServeError, Scope.Scope>;
33
+ //# sourceMappingURL=bunBridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bunBridge.d.ts","sourceRoot":"","sources":["../../../src/internal/bridge/bunBridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAI9E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAMvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,UAAU,UACd,MAAM,aACF,MAAM,qBACE,CAAC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,aAAa,SAmBzF,CAAA;AAUH;;;GAGG;AACH,eAAO,MAAM,KAAK,uRAuBhB,CAAA"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Runs a bridge program from Bun: `runProgram` makes opencode's driver from the launch options a
3
+ * host gave, and `serve` serves it on every interface of the sandbox, at a port the sandbox picks,
4
+ * until the bridge exits idle or another takes its place.
5
+ *
6
+ * Bun's server never finishes stopping once a WebSocket has been open, so it runs in a scope of its
7
+ * own, which the bridge gives a second to close after the bridge's own finalizers have run, rather
8
+ * than wait for hosts to close their connections.
9
+ */
10
+ import { BridgeServer, HostToolRelay } from "@amends-dev/harness";
11
+ import * as BunHttpServer from "@effect/platform-bun/BunHttpServer";
12
+ import * as BunRuntime from "@effect/platform-bun/BunRuntime";
13
+ import * as BunServices from "@effect/platform-bun/BunServices";
14
+ import * as Effect from "effect/Effect";
15
+ import * as Exit from "effect/Exit";
16
+ import * as Fiber from "effect/Fiber";
17
+ import * as FetchHttpClient from "effect/http/FetchHttpClient";
18
+ import * as Layer from "effect/Layer";
19
+ import * as Redacted from "effect/Redacted";
20
+ import * as Schema from "effect/Schema";
21
+ import * as Scope from "effect/Scope";
22
+ import * as Driver from "./driver.js";
23
+ /**
24
+ * Runs the bridge program of the agent `agent`, which a host launches in its sandbox. It reads the
25
+ * launch options the host gave it on standard input, makes opencode's driver from the agent options
26
+ * among them, with the sessions `makeCreateSession` creates, and serves the driver to hosts until
27
+ * it exits idle or another bridge takes its place. opencode's server exiting by itself ends it too,
28
+ * for the next host to launch both again.
29
+ *
30
+ * Beside the bridge it serves the `HostToolRelay`, through which opencode calls the host's tools,
31
+ * on 127.0.0.1 only, where opencode's server reaches it. The driver runs the opencode in
32
+ * `directory`, where the template installs it beside the program, unless the agent options name
33
+ * another command.
34
+ */
35
+ export const runProgram = (agent, directory, makeCreateSession) => BunRuntime.runMain(Effect.gen(function* () {
36
+ const launch = yield* BridgeServer.readLaunchOptions;
37
+ const options = yield* Schema.decodeUnknownEffect(Driver.Options)(launch.agentOptions);
38
+ const relay = yield* HostToolRelay.HostToolRelay;
39
+ const driver = yield* Driver.make(agent, { command: `${directory}/opencode`, ...options }, makeCreateSession(relay));
40
+ return yield* serve(driver, launch).pipe(Effect.raceFirst(Effect.andThen(driver.serverExited, Effect.fail("opencode's server exited by itself"))));
41
+ }).pipe(Effect.scoped, Effect.provide(layerRelay.pipe(Layer.provideMerge(Layer.merge(BunServices.layer, FetchHttpClient.layer))))));
42
+ /**
43
+ * The relay, on a server of its own. A call of a host's tool waits for the host for as long as an
44
+ * approval takes, so the server never closes a connection for being idle.
45
+ */
46
+ const layerRelay = HostToolRelay.layer().pipe(Layer.provide(BunHttpServer.layer({ hostname: "127.0.0.1", port: 0, idleTimeout: 0 })));
47
+ /**
48
+ * Serves `driver` to hosts as `launch` says, until the bridge exits idle, after `idleTimeout`, or
49
+ * another takes its place.
50
+ */
51
+ export const serve = Effect.fnUntraced(function* (driver, launch, options = {}) {
52
+ const serverScope = yield* Scope.make();
53
+ yield* Effect.addFinalizer(() => Effect.forkDetach(Scope.close(serverScope, Exit.void)).pipe(Effect.flatMap(Fiber.await), Effect.timeout("1 second"), Effect.ignore));
54
+ const server = yield* Layer.buildWithScope(BunHttpServer.layer({ hostname: "0.0.0.0", port: 0, disablePreemptiveShutdown: true }), serverScope);
55
+ return yield* BridgeServer.serve(driver, {
56
+ token: Redacted.make(launch.token),
57
+ bridge: launch.bridge,
58
+ stateDirectory: launch.stateDirectory,
59
+ ...options
60
+ }).pipe(Effect.provideContext(server));
61
+ });
62
+ //# sourceMappingURL=bunBridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bunBridge.js","sourceRoot":"","sources":["../../../src/internal/bridge/bunBridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * opencode's driver, which runs opencode for the bridge in its sandbox. One opencode server, which
3
+ * the driver starts when the first session starts, serves every session there, each an opencode
4
+ * session in the session's directory. The sessions are those of the API the bridge's version of
5
+ * opencode speaks: `v1/session.ts` creates them over opencode 1's session API, and `v2/session.ts`
6
+ * over opencode 2's, and each bridge program makes the driver with its own.
7
+ *
8
+ * opencode's server runs until the bridge stops. A server that fails to start is started again by
9
+ * the next session, and one that exits by itself completes `serverExited`, for the bridge to exit
10
+ * with it.
11
+ */
12
+ import type { Bridge, HarnessError } from "@amends-dev/harness";
13
+ import type * as Crypto from "effect/Crypto";
14
+ import * as Effect from "effect/Effect";
15
+ import type * as FileSystem from "effect/FileSystem";
16
+ import type * as HttpClient from "effect/http/HttpClient";
17
+ import type * as Path from "effect/Path";
18
+ import type * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
19
+ import * as Schema from "effect/Schema";
20
+ import * as Scope from "effect/Scope";
21
+ import * as Server from "./server.ts";
22
+ /** A model, as opencode names one: its provider, its id there, and a variant such as `high`. */
23
+ export declare const ModelRef: Schema.Struct<{
24
+ readonly id: Schema.String;
25
+ readonly providerID: Schema.String;
26
+ readonly variant: Schema.optionalKey<Schema.String>;
27
+ }>;
28
+ export interface ModelRef extends Schema.Schema.Type<typeof ModelRef> {
29
+ }
30
+ /** What the host gives the bridge for opencode, as its agent options. */
31
+ export declare const Options: Schema.Struct<{
32
+ /** The model a turn runs on when it names none. */
33
+ readonly model: Schema.Struct<{
34
+ readonly id: Schema.String;
35
+ readonly providerID: Schema.String;
36
+ readonly variant: Schema.optionalKey<Schema.String>;
37
+ }>;
38
+ /**
39
+ * The models a turn can name, by name. A turn that names another fails with
40
+ * `UnsupportedError`.
41
+ */
42
+ readonly models: Schema.$Record<Schema.String, Schema.Struct<{
43
+ readonly id: Schema.String;
44
+ readonly providerID: Schema.String;
45
+ readonly variant: Schema.optionalKey<Schema.String>;
46
+ }>>;
47
+ /**
48
+ * The command that runs opencode in the sandbox, when it is not the opencode the template
49
+ * installs beside the bridge program.
50
+ */
51
+ readonly command: Schema.optionalKey<Schema.String>;
52
+ /**
53
+ * opencode's configuration, as its `opencode.json` takes it, with the providers of the models.
54
+ */
55
+ readonly config: Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>;
56
+ /** Environment variables opencode runs with. */
57
+ readonly env: Schema.$Record<Schema.String, Schema.String>;
58
+ }>;
59
+ export interface Options extends Schema.Schema.Type<typeof Options> {
60
+ }
61
+ export interface Driver extends Bridge.Driver {
62
+ /**
63
+ * Completes when opencode's server exits before the bridge stops it, for the bridge to exit with
64
+ * it.
65
+ */
66
+ readonly serverExited: Effect.Effect<void>;
67
+ }
68
+ /**
69
+ * Creates a session on opencode's server, as the API of one version of opencode does: the
70
+ * session's turns run on `options`' models, and `sessionOptions` say where it works and what
71
+ * conversation it starts from. It reads the sandbox's files with the bridge's file system, and
72
+ * makes ids with its `Crypto`.
73
+ */
74
+ export type CreateSession = (server: Server.Server, options: Pick<Options, "model" | "models">, sessionOptions: Bridge.CreateSessionOptions) => Effect.Effect<Bridge.DriverSession, HarnessError.HarnessError, Scope.Scope | FileSystem.FileSystem | Crypto.Crypto>;
75
+ /**
76
+ * The driver of the agent `id`, which starts opencode's server with `options` when the first
77
+ * session starts, and creates each session on it with `createSession`. The server runs in the
78
+ * scope the driver is made in.
79
+ */
80
+ export declare const make: (id: string, options: Required<Options>, createSession: CreateSession) => Effect.Effect<Driver, never, ChildProcessSpawner.ChildProcessSpawner | Crypto.Crypto | FileSystem.FileSystem | HttpClient.HttpClient | Path.Path | Scope.Scope>;
81
+ //# sourceMappingURL=driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../../src/internal/bridge/driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAE5C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,KAAK,UAAU,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,KAAK,UAAU,MAAM,wBAAwB,CAAA;AACzD,OAAO,KAAK,KAAK,IAAI,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,KAAK,mBAAmB,MAAM,oCAAoC,CAAA;AAE9E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AAErC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,gGAAgG;AAChG,eAAO,MAAM,QAAQ;;;;EAInB,CAAA;AAEF,MAAM,WAAW,QAAS,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,QAAQ,CAAC;CAAG;AAExE,yEAAyE;AACzE,eAAO,MAAM,OAAO;IAClB,mDAAmD;;;;;;IAGnD;;;OAGG;;;;;;IAGH;;;OAGG;;IAGH;;OAEG;;IAGH,gDAAgD;;EAEhD,CAAA;AAEF,MAAM,WAAW,OAAQ,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC;CAAG;AAEtE,MAAM,WAAW,MAAO,SAAQ,MAAM,CAAC,MAAM;IAC3C;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;CAC3C;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EACrB,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CAAC,EAC1C,cAAc,EAAE,MAAM,CAAC,oBAAoB,KACxC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC,YAAY,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;AAExH;;;;GAIG;AACH,eAAO,MAAM,IAAI,2OAyCf,CAAA"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * opencode's driver, which runs opencode for the bridge in its sandbox. One opencode server, which
3
+ * the driver starts when the first session starts, serves every session there, each an opencode
4
+ * session in the session's directory. The sessions are those of the API the bridge's version of
5
+ * opencode speaks: `v1/session.ts` creates them over opencode 1's session API, and `v2/session.ts`
6
+ * over opencode 2's, and each bridge program makes the driver with its own.
7
+ *
8
+ * opencode's server runs until the bridge stops. A server that fails to start is started again by
9
+ * the next session, and one that exits by itself completes `serverExited`, for the bridge to exit
10
+ * with it.
11
+ */
12
+ import * as Deferred from "effect/Deferred";
13
+ import * as Effect from "effect/Effect";
14
+ import * as Exit from "effect/Exit";
15
+ import * as Ref from "effect/Ref";
16
+ import * as Schema from "effect/Schema";
17
+ import * as Scope from "effect/Scope";
18
+ import * as Semaphore from "effect/Semaphore";
19
+ import * as Server from "./server.js";
20
+ /** A model, as opencode names one: its provider, its id there, and a variant such as `high`. */
21
+ export const ModelRef = Schema.Struct({
22
+ id: Schema.String,
23
+ providerID: Schema.String,
24
+ variant: Schema.optionalKey(Schema.String)
25
+ });
26
+ /** What the host gives the bridge for opencode, as its agent options. */
27
+ export const Options = Schema.Struct({
28
+ /** The model a turn runs on when it names none. */
29
+ model: ModelRef,
30
+ /**
31
+ * The models a turn can name, by name. A turn that names another fails with
32
+ * `UnsupportedError`.
33
+ */
34
+ models: Schema.Record(Schema.String, ModelRef),
35
+ /**
36
+ * The command that runs opencode in the sandbox, when it is not the opencode the template
37
+ * installs beside the bridge program.
38
+ */
39
+ command: Schema.optionalKey(Schema.String),
40
+ /**
41
+ * opencode's configuration, as its `opencode.json` takes it, with the providers of the models.
42
+ */
43
+ config: Schema.Record(Schema.String, Schema.Json),
44
+ /** Environment variables opencode runs with. */
45
+ env: Schema.Record(Schema.String, Schema.String)
46
+ });
47
+ /**
48
+ * The driver of the agent `id`, which starts opencode's server with `options` when the first
49
+ * session starts, and creates each session on it with `createSession`. The server runs in the
50
+ * scope the driver is made in.
51
+ */
52
+ export const make = Effect.fnUntraced(function* (id, options, createSession) {
53
+ const services = yield* Effect.context();
54
+ const driverScope = yield* Effect.scope;
55
+ const serverExited = yield* Deferred.make();
56
+ const running = yield* Ref.make(undefined);
57
+ /** Held while the server starts, so that sessions starting together start one. */
58
+ const starting = yield* Semaphore.make(1);
59
+ /** opencode's server, which the first session to need it starts. */
60
+ const startedServer = Semaphore.withPermit(starting, Effect.gen(function* () {
61
+ const current = yield* Ref.get(running);
62
+ if (current !== undefined)
63
+ return current;
64
+ const serverScope = yield* Scope.fork(driverScope);
65
+ const server = yield* Server.start({
66
+ agent: id,
67
+ command: options.command,
68
+ config: options.config,
69
+ env: options.env
70
+ }).pipe(Scope.provide(serverScope), Effect.onError((cause) => Scope.close(serverScope, Exit.failCause(cause))));
71
+ yield* Effect.forkIn(Effect.andThen(server.exited, Deferred.succeed(serverExited, undefined)), serverScope);
72
+ yield* Ref.set(running, server);
73
+ return server;
74
+ })).pipe(Effect.provide(services));
75
+ const driver = {
76
+ id,
77
+ serverExited: Deferred.await(serverExited),
78
+ createSession: (sessionOptions) => Effect.flatMap(startedServer, (server) => createSession(server, options, sessionOptions).pipe(Effect.provide(services)))
79
+ };
80
+ return driver;
81
+ });
82
+ //# sourceMappingURL=driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.js","sourceRoot":"","sources":["../../../src/internal/bridge/driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The host's tools as both versions of opencode reach them: through the bridge's `HostToolRelay`,
3
+ * an MCP server that opencode connects to for each session's directory as `host`, presenting the
4
+ * session's token. opencode lists an MCP server's tools when it connects, so the session connects
5
+ * it again whenever a turn's tools change, and disconnects it for a turn without any.
6
+ */
7
+ import type { Bridge, HarnessError, HostToolRelay } from "@amends-dev/harness";
8
+ import * as Effect from "effect/Effect";
9
+ /** The name the relay's MCP server has in opencode. */
10
+ export declare const serverName = "host";
11
+ /** An MCP server the agent connects to over HTTP, presenting `headers`. */
12
+ export interface RemoteMcpServer {
13
+ readonly url: string;
14
+ readonly headers: Readonly<Record<string, string>>;
15
+ }
16
+ /** How a session's directory adds, connects, and disconnects the relay's MCP server. */
17
+ export interface McpServers {
18
+ readonly add: (server: RemoteMcpServer) => Effect.Effect<void, HarnessError.HarnessError>;
19
+ readonly reconnect: Effect.Effect<void, HarnessError.HarnessError>;
20
+ readonly disconnect: Effect.Effect<void, HarnessError.HarnessError>;
21
+ }
22
+ /**
23
+ * The function that has opencode list a turn's `tools` from the relay at `relayUrl` for the
24
+ * session `relaySession` opened, through `mcpServers`, doing nothing while they are the ones it
25
+ * lists already.
26
+ */
27
+ export declare const makeLister: (relayUrl: string, relaySession: HostToolRelay.RelaySession, mcpServers: McpServers) => Effect.Effect<(tools: readonly Bridge.ToolDefinition[]) => Effect.Effect<void, HarnessError.HarnessError, never>, never, never>;
28
+ //# sourceMappingURL=hostTools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostTools.d.ts","sourceRoot":"","sources":["../../../src/internal/bridge/hostTools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAC9E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAIvC,uDAAuD;AACvD,eAAO,MAAM,UAAU,SAAS,CAAA;AAEhC,2EAA2E;AAC3E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CACnD;AAED,wFAAwF;AACxF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,YAAY,CAAC,CAAA;IACzF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,YAAY,CAAC,CAAA;IAClE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,YAAY,CAAC,CAAA;CACpE;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,yNAwBrB,CAAA"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The host's tools as both versions of opencode reach them: through the bridge's `HostToolRelay`,
3
+ * an MCP server that opencode connects to for each session's directory as `host`, presenting the
4
+ * session's token. opencode lists an MCP server's tools when it connects, so the session connects
5
+ * it again whenever a turn's tools change, and disconnects it for a turn without any.
6
+ */
7
+ import * as Effect from "effect/Effect";
8
+ import * as Redacted from "effect/Redacted";
9
+ import * as Ref from "effect/Ref";
10
+ /** The name the relay's MCP server has in opencode. */
11
+ export const serverName = "host";
12
+ /**
13
+ * The function that has opencode list a turn's `tools` from the relay at `relayUrl` for the
14
+ * session `relaySession` opened, through `mcpServers`, doing nothing while they are the ones it
15
+ * lists already.
16
+ */
17
+ export const makeLister = Effect.fnUntraced(function* (relayUrl, relaySession, mcpServers) {
18
+ /** The tools opencode lists, as JSON, or nothing while it lists none. */
19
+ const listed = yield* Ref.make(undefined);
20
+ const added = yield* Ref.make(false);
21
+ return Effect.fnUntraced(function* (tools) {
22
+ const wanted = tools.length === 0 ? undefined : JSON.stringify(tools);
23
+ if (wanted === (yield* Ref.get(listed)))
24
+ return;
25
+ if (wanted === undefined) {
26
+ yield* mcpServers.disconnect;
27
+ }
28
+ else if (yield* Ref.get(added)) {
29
+ yield* mcpServers.reconnect;
30
+ }
31
+ else {
32
+ yield* mcpServers.add({
33
+ url: relayUrl,
34
+ headers: { authorization: `Bearer ${Redacted.value(relaySession.token)}` }
35
+ });
36
+ yield* Ref.set(added, true);
37
+ }
38
+ yield* Ref.set(listed, wanted);
39
+ });
40
+ });
41
+ //# sourceMappingURL=hostTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostTools.js","sourceRoot":"","sources":["../../../src/internal/bridge/hostTools.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,GAAG,MAAM,YAAY,CAAA;AAEjC,uDAAuD;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAA;AAehC;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EACnD,QAAgB,EAChB,YAAwC,EACxC,UAAsB;IAEtB,yEAAyE;IACzE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAqB,SAAS,CAAC,CAAA;IAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACpC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,KAA2C;QAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;QACrE,IAAI,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAAE,OAAM;QAC/C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAA;QAC9B,CAAC;aAAM,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,KAAK,CAAC,CAAC,UAAU,CAAC,SAAS,CAAA;QAC7B,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;gBACpB,GAAG,EAAE,QAAQ;gBACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,EAAE;aAC3E,CAAC,CAAA;YACF,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAC7B,CAAC;QACD,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * opencode's server, which the bridge starts in its sandbox. One server serves every session in the
3
+ * sandbox, each in its own directory. `start` runs the server until the scope closes, listening
4
+ * only on 127.0.0.1, behind a password that `start` makes and gives the server in its environment.
5
+ * `start` picks a free port for it, since opencode takes port 0 as its default port, 4096, where
6
+ * the server of a bridge with other options may listen already. The bridge is the server's only
7
+ * client and lives exactly as long as it, so the password is kept nowhere else. The requests the
8
+ * bridge makes of the server are those of the API its version of opencode speaks, in `v1/api.ts`
9
+ * and `v2/api.ts`, over the client `start` returns.
10
+ *
11
+ * opencode reads the configuration `start` is given from a directory that `start` makes for it and
12
+ * removes when the scope closes, in place of the global configuration of the sandbox's user, which
13
+ * opencode would read from under the home directory. A project's own configuration, in the
14
+ * directory a session works in, applies over it.
15
+ *
16
+ * opencode's tools run with the server's environment, so the agent can read the password; it keeps
17
+ * out everything else on the machine. A failed request fails with the `HarnessError` the driver
18
+ * reports, naming the agent, as `requestError` maps it.
19
+ */
20
+ import { HarnessError } from "@amends-dev/harness";
21
+ import * as Crypto from "effect/Crypto";
22
+ import * as Effect from "effect/Effect";
23
+ import type * as Sse from "effect/encoding/Sse";
24
+ import * as FileSystem from "effect/FileSystem";
25
+ import * as HttpClient from "effect/http/HttpClient";
26
+ import type * as HttpClientError from "effect/http/HttpClientError";
27
+ import * as Path from "effect/Path";
28
+ import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner";
29
+ import type * as Record from "effect/Record";
30
+ import type * as Schema from "effect/Schema";
31
+ export interface Options {
32
+ /** The agent the server runs for, which its errors name, such as `opencode`. */
33
+ readonly agent: string;
34
+ /** The command that runs opencode, such as `opencode`. */
35
+ readonly command: string;
36
+ /** opencode's configuration, as its `opencode.json` takes it. */
37
+ readonly config: {
38
+ readonly [key: string]: Schema.Json;
39
+ };
40
+ /** Environment variables opencode runs with. */
41
+ readonly env: Record.ReadonlyRecord<string, string>;
42
+ }
43
+ export interface Server {
44
+ /** The agent the server runs for, which the errors of its requests name. */
45
+ readonly agent: string;
46
+ /** Completes when the server exits, which it does before the scope closes only when it fails. */
47
+ readonly exited: Effect.Effect<void>;
48
+ /** A client of the server, at its URL, presenting its password. It answers every status. */
49
+ readonly client: HttpClient.HttpClient;
50
+ /** `client`, failing with the responses whose status is not a success. */
51
+ readonly clientOk: HttpClient.HttpClient;
52
+ }
53
+ /** Starts the server, which runs until the scope closes, and waits until it listens. */
54
+ export declare const start: (options: Options) => Effect.Effect<Server, HarnessError.HarnessError, ChildProcessSpawner.ChildProcessSpawner | Crypto.Crypto | FileSystem.FileSystem | HttpClient.HttpClient | Path.Path | import("effect/Scope").Scope>;
55
+ /** The error that `agent` reports for `reason`. */
56
+ export declare const harnessError: (agent: string, reason: HarnessError.HarnessErrorReason, cause?: unknown) => HarnessError.HarnessError;
57
+ /**
58
+ * The error `agent` reports for a request that failed with `error`: `UnavailableError` for a server
59
+ * it cannot reach, one that asks to be retried, or one that failed; `NotFoundError` for what the
60
+ * server has no record of; `AgentContractError` for an answer the agent cannot read; and
61
+ * `UnknownError` for the rest.
62
+ */
63
+ export declare const requestError: (agent: string) => (error: HttpClientError.HttpClientError | Schema.SchemaError | Sse.SseError | Sse.Retry) => HarnessError.HarnessError;
64
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/internal/bridge/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,KAAK,KAAK,GAAG,MAAM,qBAAqB,CAAA;AAC/C,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAA;AAE/C,OAAO,KAAK,UAAU,MAAM,wBAAwB,CAAA;AACpD,OAAO,KAAK,KAAK,eAAe,MAAM,6BAA6B,CAAA;AAGnE,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AAGnC,OAAO,KAAK,mBAAmB,MAAM,oCAAoC,CAAA;AACzE,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAE5C,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAA;AAG5C,MAAM,WAAW,OAAO;IACtB,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IAEtB,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IAExB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,IAAI,CAAA;KAAE,CAAA;IAExD,gDAAgD;IAChD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,MAAM;IACrB,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IAEtB,iGAAiG;IACjG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAEpC,4FAA4F;IAC5F,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,UAAU,CAAA;IAEtC,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAA;CACzC;AAED,wFAAwF;AACxF,eAAO,MAAM,KAAK,4NAkDjB,CAAA;AA0CD,mDAAmD;AACnD,eAAO,MAAM,YAAY,UAAW,MAAM,UAAU,YAAY,CAAC,kBAAkB,UAAU,OAAO,8BAC3C,CAAA;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,YAAY,UACf,MAAM,aAAa,eAAe,CAAC,eAAe,GAAG,MAAM,CAAC,WAAW,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,KAAK,8BAyBtG,CAAA"}