@codeworksh/cli 0.2.0-canary.17.1.gd1cf9b0f → 0.2.0-canary.18.1.gc4473ccb

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 (66) hide show
  1. package/{acp-BlTh2na0.mjs → acp-_82hEgSL.mjs} +4 -4
  2. package/{acp-BlTh2na0.mjs.map → acp-_82hEgSL.mjs.map} +1 -1
  3. package/{add-DlwSE-gO.mjs → add-Cih66f0Z.mjs} +2 -2
  4. package/{add-DlwSE-gO.mjs.map → add-Cih66f0Z.mjs.map} +1 -1
  5. package/{catalog-BDSnGfE_.mjs → catalog-C1G3pzHZ.mjs} +2 -2
  6. package/{catalog-BDSnGfE_.mjs.map → catalog-C1G3pzHZ.mjs.map} +1 -1
  7. package/{check-CpZTFCDq.mjs → check-CWXDjuC1.mjs} +2 -2
  8. package/{check-CpZTFCDq.mjs.map → check-CWXDjuC1.mjs.map} +1 -1
  9. package/{identity-KihnHS0K.mjs → identity-BfMXCqOi.mjs} +2 -2
  10. package/{identity-KihnHS0K.mjs.map → identity-BfMXCqOi.mjs.map} +1 -1
  11. package/index.mjs +25 -25
  12. package/{install-CNWMNyaf.mjs → install-CRGaL_bc.mjs} +2 -2
  13. package/{install-CNWMNyaf.mjs.map → install-CRGaL_bc.mjs.map} +1 -1
  14. package/{link-oTpS3aUc.mjs → link-BiwLQTXW.mjs} +2 -2
  15. package/{link-oTpS3aUc.mjs.map → link-BiwLQTXW.mjs.map} +1 -1
  16. package/{list-CmHTTB8Z.mjs → list-BvBVZtHt.mjs} +3 -3
  17. package/{list-CmHTTB8Z.mjs.map → list-BvBVZtHt.mjs.map} +1 -1
  18. package/{list-DhdnHHJ5.mjs → list-Daq_zh4E.mjs} +2 -2
  19. package/{list-DhdnHHJ5.mjs.map → list-Daq_zh4E.mjs.map} +1 -1
  20. package/{login-DPJbdjAY.mjs → login-lsagcqp6.mjs} +3 -3
  21. package/{login-DPJbdjAY.mjs.map → login-lsagcqp6.mjs.map} +1 -1
  22. package/{logout-CL5CN_af.mjs → logout-DdkYEWM6.mjs} +3 -3
  23. package/{logout-CL5CN_af.mjs.map → logout-DdkYEWM6.mjs.map} +1 -1
  24. package/package-DU3nL58b.mjs +6 -0
  25. package/package-DU3nL58b.mjs.map +1 -0
  26. package/package.json +5 -4
  27. package/{providers-Dg8UlU_O.mjs → providers-CZmPKpb_.mjs} +3 -3
  28. package/{providers-Dg8UlU_O.mjs.map → providers-CZmPKpb_.mjs.map} +1 -1
  29. package/{refresh-OsgI6DYK.mjs → refresh-BFxZjrH1.mjs} +3 -3
  30. package/{refresh-OsgI6DYK.mjs.map → refresh-BFxZjrH1.mjs.map} +1 -1
  31. package/{refresh-TK948P0j.mjs → refresh-Cbq-iY3f.mjs} +3 -3
  32. package/{refresh-TK948P0j.mjs.map → refresh-Cbq-iY3f.mjs.map} +1 -1
  33. package/{reload-_hDmESKE.mjs → reload-C6c48hBY.mjs} +2 -2
  34. package/{reload-_hDmESKE.mjs.map → reload-C6c48hBY.mjs.map} +1 -1
  35. package/{remove-DjBJe09T.mjs → remove-lig66J-D.mjs} +2 -2
  36. package/{remove-DjBJe09T.mjs.map → remove-lig66J-D.mjs.map} +1 -1
  37. package/{restart-BhtiQrRP.mjs → restart-Bjpvhor3.mjs} +3 -3
  38. package/{restart-BhtiQrRP.mjs.map → restart-Bjpvhor3.mjs.map} +1 -1
  39. package/{run-DKKbRyIo.mjs → run-DIFNYGN-.mjs} +4 -4
  40. package/run-DIFNYGN-.mjs.map +1 -0
  41. package/{runtime-CIBm_3RX.mjs → runtime-B43doHjV.mjs} +69 -6
  42. package/runtime-B43doHjV.mjs.map +1 -0
  43. package/{serve-b4kh1Ncm.mjs → serve-CQy0Xqv6.mjs} +12 -8
  44. package/serve-CQy0Xqv6.mjs.map +1 -0
  45. package/{service-Eeg2xnZm.mjs → service-BnbxCw8H.mjs} +2 -2
  46. package/{service-Eeg2xnZm.mjs.map → service-BnbxCw8H.mjs.map} +1 -1
  47. package/{shared-DjyUhNsi.mjs → shared-wNZoC017.mjs} +2 -2
  48. package/{shared-DjyUhNsi.mjs.map → shared-wNZoC017.mjs.map} +1 -1
  49. package/{start-nYFn6dNR.mjs → start-DO3HjkNR.mjs} +3 -3
  50. package/{start-nYFn6dNR.mjs.map → start-DO3HjkNR.mjs.map} +1 -1
  51. package/{status-DShPzrgm.mjs → status-BQcs5jvy.mjs} +3 -3
  52. package/{status-DShPzrgm.mjs.map → status-BQcs5jvy.mjs.map} +1 -1
  53. package/{status-BTCqpq7x.mjs → status-CQHqU7_7.mjs} +3 -3
  54. package/{status-BTCqpq7x.mjs.map → status-CQHqU7_7.mjs.map} +1 -1
  55. package/{stop-Bx6q-OsW.mjs → stop-CbszhOq5.mjs} +3 -3
  56. package/{stop-Bx6q-OsW.mjs.map → stop-CbszhOq5.mjs.map} +1 -1
  57. package/{tui-ChaAFDdS.mjs → tui-CxBfJvv5.mjs} +5 -5
  58. package/tui-CxBfJvv5.mjs.map +1 -0
  59. package/{update-6Fn2_4fJ.mjs → update-CfrkcWoW.mjs} +2 -2
  60. package/{update-6Fn2_4fJ.mjs.map → update-CfrkcWoW.mjs.map} +1 -1
  61. package/package-8_CE-vpn.mjs +0 -6
  62. package/package-8_CE-vpn.mjs.map +0 -1
  63. package/run-DKKbRyIo.mjs.map +0 -1
  64. package/runtime-CIBm_3RX.mjs.map +0 -1
  65. package/serve-b4kh1Ncm.mjs.map +0 -1
  66. package/tui-ChaAFDdS.mjs.map +0 -1
@@ -1,15 +1,15 @@
1
- import { i as Cmd, t as handler } from "./runtime-CIBm_3RX.mjs";
1
+ import { i as Cmd, t as handler } from "./runtime-B43doHjV.mjs";
2
2
  import { _ as path, b as encode, g as OAuthError, h as Api, r as renderError, u as writeError, v as Connected, y as Core } from "./error-CzUxh0Q9.mjs";
3
3
  import { t as harnessOptions } from "./harness-6d8TlAVk.mjs";
4
- import { c as register, r as layer$4, s as log, t as Service$2 } from "./identity-KihnHS0K.mjs";
4
+ import { c as register, r as layer$4, s as log, t as Service$2 } from "./identity-BfMXCqOi.mjs";
5
5
  import { Cause, Context, Effect, FileSystem, Layer, Logger, Option, Queue, Stream } from "effect";
6
+ import { HttpRouter, HttpServer } from "effect/http";
6
7
  import { Control, Event, EventRegistry, EventSchema, Global, Harness, PromptSchema, Sandbox, Session, SessionStore, State } from "@codeworksh/harness/effect";
7
8
  import { NodeHttpServer } from "@effect/platform-node";
8
9
  import { RpcSerialization, RpcServer } from "effect/rpc";
9
10
  import { summarizeGitHubCopilot, summarizeOpenAICodex } from "@codeworksh/aikit/oauth/summary";
10
11
  import { GitHubCopilotOAuthClient, JsonGitHubCopilotAuthStorage } from "@codeworksh/aikit/oauth/github/copilot";
11
12
  import { JsonOpenAICodexAuthStorage, OpenAICodexOAuthClient } from "@codeworksh/aikit/oauth/openai/codex";
12
- import { HttpRouter, HttpServer } from "effect/http";
13
13
  import * as NetAddress from "effect/net/NetAddress";
14
14
  import { createServer } from "node:http";
15
15
  var Service$1 = class extends Context.Service()("@codeworksh/cli/server/feed/Service") {};
@@ -144,6 +144,10 @@ const sessionInfo = Effect.fn("Server.sessionInfo")(function* (sessionId) {
144
144
  if (Option.isNone(found)) return yield* new SessionStore.SessionNotFoundError({ sessionId });
145
145
  return toSessionInfo(yield* found.value.info);
146
146
  });
147
+ const exported = (name, self) => self.pipe(Effect.withSpan(name, {
148
+ level: "Info",
149
+ root: true
150
+ }));
147
151
  const releaseOnFailure = (selection) => selection?.created && selection.info !== void 0 ? Sandbox.stop(selection.info.id).pipe(Effect.catchCause(Effect.logError)) : Effect.void;
148
152
  const layer$1 = Api.toLayer(Effect.gen(function* () {
149
153
  const control = yield* Control.Service;
@@ -162,7 +166,7 @@ const layer$1 = Api.toLayer(Effect.gen(function* () {
162
166
  "auth.refresh": ({ provider }) => oauth.refresh(provider),
163
167
  "auth.logout": ({ provider }) => oauth.logout(provider),
164
168
  "session.create": Effect.fnUntraced(function* ({ title, directory, hostDir, sandbox, runtime }) {
165
- const selection = sandbox === void 0 ? void 0 : yield* Sandbox.resolve(sandbox);
169
+ const selection = sandbox === void 0 ? void 0 : yield* exported("Server.session.create", Sandbox.resolve(sandbox));
166
170
  const selected = selection?.info;
167
171
  const handle = yield* Session.create({
168
172
  ...title === void 0 ? {} : { title },
@@ -198,7 +202,7 @@ const layer$1 = Api.toLayer(Effect.gen(function* () {
198
202
  return toSessionInfo(yield* handle.info);
199
203
  }),
200
204
  "session.relink": Effect.fnUntraced(function* ({ sessionId, sandbox, directory }) {
201
- const selection = sandbox === void 0 ? void 0 : yield* Sandbox.resolve(sandbox);
205
+ const selection = sandbox === void 0 ? void 0 : yield* exported("Server.session.relink", Sandbox.resolve(sandbox));
202
206
  const selected = selection?.info;
203
207
  const handle = yield* Session.relink({
204
208
  sessionId,
@@ -235,7 +239,7 @@ const layer$1 = Api.toLayer(Effect.gen(function* () {
235
239
  return (yield* Sandbox.list()).map(toSandboxInfo);
236
240
  }),
237
241
  "sandbox.create": Effect.fnUntraced(function* ({ driver }) {
238
- return toSandboxInfo(yield* Sandbox.create({ driver }));
242
+ return toSandboxInfo(yield* exported("Server.sandbox.create", Sandbox.create({ driver })));
239
243
  }),
240
244
  "sandbox.register": Effect.fnUntraced(function* ({ driver, providerResourceId }) {
241
245
  return toSandboxInfo(yield* Sandbox.register({
@@ -312,7 +316,7 @@ const failed = Effect.sync(() => {
312
316
  process.exitCode = 1;
313
317
  });
314
318
  const report = (error) => writeError(renderError(error)).pipe(Effect.andThen(failed));
315
- var serve_default = handler(Cmd.commands.serve, Effect.fn("CLI.serve")(function* ({ host, port, service }) {
319
+ var serve_default = handler(Cmd.commands.serve, Effect.fn("CLI.serve", { level: "Info" })(function* ({ host, port, service }) {
316
320
  const shared = yield* Cmd.spec;
317
321
  const harness = {
318
322
  ...harnessOptions(shared),
@@ -334,4 +338,4 @@ var serve_default = handler(Cmd.commands.serve, Effect.fn("CLI.serve")(function*
334
338
  //#endregion
335
339
  export { serve_default as default };
336
340
 
337
- //# sourceMappingURL=serve-b4kh1Ncm.mjs.map
341
+ //# sourceMappingURL=serve-CQy0Xqv6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve-CQy0Xqv6.mjs","names":["Service","Envelope.Core","Envelope.encode","layer","layer","Contract.OAuthError","layer","EventFeed.Service","OAuth.Service","Identity.Service","Identity.Service","Contract.path","Registration.register","Contract.Api","EventFeed.layer","OAuth.layer","Identity.layer","Runtime.handler","Server.layer","Registration.log"],"sources":["../../src/server/feed.ts","../../src/server/oauth.ts","../../src/server/handlers.ts","../../src/server/server.ts","../../src/cli/cmd/handlers/serve.ts"],"sourcesContent":["import { Event, EventRegistry, EventSchema } from \"@codeworksh/harness/effect\";\nimport { Cause, Context, Effect, Layer, Queue, Scope, Stream } from \"effect\";\nimport { EncodingError, type EventEnvelope, Envelope } from \"./envelope.ts\";\n\nexport const SubscriberCapacity = 4096;\n\nexport type Error = Event.SubscriptionOverflowError | EncodingError;\n\nexport interface Interface {\n\t/** A live envelope stream for one client; releasing the scope unregisters it. */\n\treadonly subscribe: Effect.Effect<Stream.Stream<EventEnvelope, Error>, never, Scope.Scope>;\n}\n\nexport class Service extends Context.Service<Service, Interface>()(\"@codeworksh/cli/server/feed/Service\") {}\n\n/**\n * Fan-out for `event.subscribe`. One listener on the event bus encodes each\n * event once and hands the same envelope to every client, rather than every\n * client re-encoding the same payload.\n *\n * Failure is per-cause, not per-feed: a client that cannot keep up fails alone\n * with its own overflow, while an event that cannot be encoded is a server bug\n * that disconnects everyone currently attached -- the feed stays usable for\n * whoever connects next. Types outside the server's registry are dropped\n * before they can consume a client's capacity.\n */\nexport const make = Effect.fn(\"EventFeed.make\")(function* (\n\tlisten: (subscriber: Event.Subscriber) => Effect.Effect<Event.Unsubscribe>,\n\toptions?: { readonly capacity?: number; readonly registry?: Envelope.Registry },\n) {\n\tconst capacity = options?.capacity ?? SubscriberCapacity;\n\t// Whatever this server knows how to describe, plugin registrations included.\n\tconst registry = options?.registry ?? Envelope.Core;\n\tconst subscribers = new Set<Queue.Queue<EventEnvelope, Error>>();\n\n\tconst failAll = (error: Error) =>\n\t\tEffect.sync(() => {\n\t\t\tconst current = Array.from(subscribers);\n\t\t\tsubscribers.clear();\n\t\t\tfor (const subscriber of current) Queue.failCauseUnsafe(subscriber, Cause.fail(error));\n\t\t});\n\n\tconst deliver = Effect.fnUntraced(function* (event: EventSchema.Payload) {\n\t\tif (subscribers.size === 0) return;\n\t\t// Dropped here rather than after the queue: a burst of events this server\n\t\t// cannot describe must not spend a client's capacity on its way to nowhere.\n\t\tif (registry(event.type) === undefined) return;\n\t\tconst envelope = yield* Envelope.encode(event, registry);\n\t\tfor (const subscriber of subscribers) {\n\t\t\tif (Queue.offerUnsafe(subscriber, envelope)) continue;\n\t\t\tsubscribers.delete(subscriber);\n\t\t\tQueue.failCauseUnsafe(subscriber, Cause.fail(new Event.SubscriptionOverflowError({ capacity })));\n\t\t}\n\t});\n\n\tconst publish = (event: EventSchema.Payload) =>\n\t\tdeliver(event).pipe(\n\t\t\tEffect.catchTags({\n\t\t\t\tEventEncodingError: (error) =>\n\t\t\t\t\tEffect.logError(\"Failed to encode public event\", { type: error.type, cause: error.cause }).pipe(\n\t\t\t\t\t\tEffect.andThen(failAll(error)),\n\t\t\t\t\t),\n\t\t\t\t// The registry guard in `deliver` already returned for unknown types.\n\t\t\t\tUnknownEventTypeError: Effect.die,\n\t\t\t}),\n\t\t);\n\n\tconst unsubscribe = yield* listen(publish);\n\tyield* Effect.addFinalizer(() => unsubscribe);\n\n\treturn Service.of({\n\t\tsubscribe: Effect.acquireRelease(\n\t\t\tQueue.dropping<EventEnvelope, Error>(capacity).pipe(\n\t\t\t\tEffect.tap((queue) => Effect.sync(() => subscribers.add(queue))),\n\t\t\t),\n\t\t\t(queue) => Effect.sync(() => subscribers.delete(queue)).pipe(Effect.andThen(Queue.shutdown(queue))),\n\t\t).pipe(Effect.map(Stream.fromQueue)),\n\t});\n});\n\nexport const layer = Layer.effect(\n\tService,\n\tEffect.gen(function* () {\n\t\tconst events = yield* Event.Service;\n\t\tconst registered = yield* EventRegistry.Service;\n\t\treturn yield* make(events.listen, { registry: registered.get });\n\t}),\n);\n\nexport * as EventFeed from \"./feed.ts\";\n","/**\n * Server-side OAuth credential storage.\n *\n * The CLI runs the interactive part of every login locally — a browser\n * callback or a device code cannot travel over RPC — and sends the resulting\n * credentials here, so this service only ever reads, writes, refreshes and\n * clears the server home's `auth.json`.\n */\nimport {\n\tGitHubCopilotOAuthClient,\n\tJsonGitHubCopilotAuthStorage,\n\ttype GitHubCopilotOAuthCredentials,\n} from \"@codeworksh/aikit/oauth/github/copilot\";\nimport {\n\tJsonOpenAICodexAuthStorage,\n\tOpenAICodexOAuthClient,\n\ttype OpenAICodexOAuthCredentials,\n} from \"@codeworksh/aikit/oauth/openai/codex\";\nimport { summarizeGitHubCopilot, summarizeOpenAICodex } from \"@codeworksh/aikit/oauth/summary\";\nimport { Global } from \"@codeworksh/harness/effect\";\nimport { Context, Effect, Layer } from \"effect\";\nimport { Contract } from \"./contract.ts\";\n\ninterface Interface {\n\treadonly save: (credentials: Contract.OAuthCredentials) => Effect.Effect<Contract.OAuthInfo, Contract.OAuthError>;\n\treadonly status: (provider: Contract.OAuthProvider) => Effect.Effect<Contract.OAuthInfo | null, Contract.OAuthError>;\n\treadonly refresh: (\n\t\tprovider: Contract.OAuthProvider,\n\t) => Effect.Effect<Contract.OAuthInfo | null, Contract.OAuthError>;\n\treadonly logout: (provider: Contract.OAuthProvider) => Effect.Effect<void, Contract.OAuthError>;\n}\n\nexport class Service extends Context.Service<Service, Interface>()(\"@codeworksh/cli/server/oauth/Service\") {}\n\nconst message = (cause: unknown): string =>\n\tcause instanceof Error && cause.message.trim().length > 0 ? cause.message : String(cause);\n\n/**\n * Re-exported so the server, the CLI and aikit all describe a login the same\n * way; `Contract.OAuthInfo` is the wire shape of {@link OAuthSummary}.\n */\nexport const codexInfo = summarizeOpenAICodex;\nexport const copilotInfo = summarizeGitHubCopilot;\n\nexport const layer = (options: { readonly home?: string | undefined } = {}) =>\n\tLayer.effect(\n\t\tService,\n\t\tEffect.gen(function* () {\n\t\t\tconst global = yield* Global.Service;\n\t\t\tconst authFile = Global.authFile(options.home === undefined ? undefined : global.home);\n\t\t\tconst file = authFile === undefined ? {} : { path: authFile };\n\t\t\tconst codex = new OpenAICodexOAuthClient({ storage: new JsonOpenAICodexAuthStorage(file) });\n\t\t\tconst copilot = new GitHubCopilotOAuthClient({ storage: new JsonGitHubCopilotAuthStorage(file) });\n\t\t\tconst attempt = <A>(run: () => Promise<A>) =>\n\t\t\t\tEffect.tryPromise({\n\t\t\t\t\ttry: run,\n\t\t\t\t\tcatch: (cause) => new Contract.OAuthError({ message: message(cause) }),\n\t\t\t\t});\n\t\t\tconst optional = <A>(run: () => Promise<A | undefined>, info: (value: A) => Contract.OAuthInfo) =>\n\t\t\t\tattempt(run).pipe(Effect.map((value) => (value === undefined ? null : info(value))));\n\n\t\t\treturn Service.of({\n\t\t\t\t// The `provider` tag is routing, not a credential: it never reaches disk.\n\t\t\t\tsave: (wire) => {\n\t\t\t\t\tif (wire.provider === \"openai-codex\") {\n\t\t\t\t\t\tconst credentials: OpenAICodexOAuthCredentials = {\n\t\t\t\t\t\t\taccess: wire.access,\n\t\t\t\t\t\t\trefresh: wire.refresh,\n\t\t\t\t\t\t\texpires: wire.expires,\n\t\t\t\t\t\t\taccountId: wire.accountId,\n\t\t\t\t\t\t};\n\t\t\t\t\t\treturn attempt(() => codex.storage.set(credentials)).pipe(Effect.as(codexInfo(credentials)));\n\t\t\t\t\t}\n\t\t\t\t\tconst credentials: GitHubCopilotOAuthCredentials = {\n\t\t\t\t\t\taccess: wire.access,\n\t\t\t\t\t\trefresh: wire.refresh,\n\t\t\t\t\t\texpires: wire.expires,\n\t\t\t\t\t\t...(wire.enterpriseUrl === undefined ? {} : { enterpriseUrl: wire.enterpriseUrl }),\n\t\t\t\t\t\t...(wire.apiEndpoint === undefined ? {} : { apiEndpoint: wire.apiEndpoint }),\n\t\t\t\t\t\t...(wire.availableModelIds === undefined ? {} : { availableModelIds: [...wire.availableModelIds] }),\n\t\t\t\t\t};\n\t\t\t\t\treturn attempt(() => copilot.storage.set(credentials)).pipe(Effect.as(copilotInfo(credentials)));\n\t\t\t\t},\n\t\t\t\tstatus: (provider) =>\n\t\t\t\t\tprovider === \"openai-codex\"\n\t\t\t\t\t\t? optional(() => codex.storage.get(), codexInfo)\n\t\t\t\t\t\t: optional(() => copilot.storage.get(), copilotInfo),\n\t\t\t\t// GitHub OAuth tokens never expire, so a Copilot \"refresh\" is a read.\n\t\t\t\trefresh: (provider) =>\n\t\t\t\t\tprovider === \"openai-codex\"\n\t\t\t\t\t\t? optional(() => codex.getCredentials(), codexInfo)\n\t\t\t\t\t\t: optional(() => copilot.getCredentials(), copilotInfo),\n\t\t\t\tlogout: (provider) => attempt(() => (provider === \"openai-codex\" ? codex.logout() : copilot.logout())),\n\t\t\t});\n\t\t}),\n\t);\n\nexport * as OAuth from \"./oauth.ts\";\n","import { Control, EventSchema, PromptSchema, Sandbox, Session, SessionStore, State } from \"@codeworksh/harness/effect\";\nimport { Effect, Option, Stream } from \"effect\";\nimport { Contract, type RuntimeConfig, type SandboxInfo, type SessionInfo } from \"./contract.ts\";\nimport { Envelope } from \"./envelope.ts\";\nimport { EventFeed } from \"./feed.ts\";\nimport { Identity } from \"./identity.ts\";\nimport { OAuth } from \"./oauth.ts\";\n\nconst toSandboxInfo = (info: Sandbox.Info): SandboxInfo => ({\n\tid: info.id,\n\tdriver: info.driver,\n\tkind: info.kind,\n\tproviderResourceId: info.providerResourceId,\n\townership: info.ownership,\n\tstatus: info.status,\n\tusage: info.usage,\n\trefCount: info.refCount,\n\tcreatedAt: info.createdAt,\n\tupdatedAt: info.updatedAt,\n});\n\nconst toSessionInfo = (info: Session.Info): SessionInfo => ({\n\tid: info.id,\n\ttitle: info.title,\n\tdirectory: info.directory,\n\t...(info.hostDir === undefined ? {} : { hostDir: info.hostDir }),\n\t...(info.sandbox === undefined ? {} : { sandbox: toSandboxInfo(info.sandbox) }),\n});\n\n// Wire configs name only the keys they set, so `undefined` never reaches the\n// harness inputs under exactOptionalPropertyTypes.\nconst runtimeInput = (runtime: RuntimeConfig | undefined): Session.RuntimeInput => ({\n\t...(runtime?.model === undefined ? {} : { model: runtime.model }),\n\t...(runtime?.thinkingLevel === undefined ? {} : { thinkingLevel: runtime.thinkingLevel }),\n});\n\nconst sessionInfo = Effect.fn(\"Server.sessionInfo\")(function* (sessionId: Session.SessionSchema.ID) {\n\tconst found = yield* Session.get(sessionId);\n\tif (Option.isNone(found)) return yield* new SessionStore.SessionNotFoundError({ sessionId });\n\treturn toSessionInfo(yield* found.value.info);\n});\n\n// RpcServer's request span has no level, so it is Debug and drops every Info span under it.\n// Provisioning a sandbox is worth exporting, so it starts a trace of its own.\nconst exported = <A, E, R>(name: string, self: Effect.Effect<A, E, R>) =>\n\tself.pipe(Effect.withSpan(name, { level: \"Info\", root: true }));\n\nconst releaseOnFailure = (selection: Effect.Success<ReturnType<typeof Sandbox.resolve>> | undefined) =>\n\tselection?.created && selection.info !== undefined\n\t\t? Sandbox.stop(selection.info.id).pipe(Effect.catchCause(Effect.logError))\n\t\t: Effect.void;\n\nexport const layer = Contract.Api.toLayer(\n\tEffect.gen(function* () {\n\t\tconst control = yield* Control.Service;\n\t\tconst feed = yield* EventFeed.Service;\n\t\tconst sessions = yield* SessionStore.Service;\n\t\tconst state = yield* State.Service;\n\t\tconst oauth = yield* OAuth.Service;\n\t\tconst identity = yield* Identity.Service;\n\n\t\treturn Contract.Api.of({\n\t\t\t\"server.info\": () => Effect.succeed({ pid: identity.pid, version: identity.version }),\n\t\t\t\"auth.save\": ({ credentials }) => oauth.save(credentials),\n\t\t\t\"auth.status\": ({ provider }) => oauth.status(provider),\n\t\t\t\"auth.refresh\": ({ provider }) => oauth.refresh(provider),\n\t\t\t\"auth.logout\": ({ provider }) => oauth.logout(provider),\n\t\t\t\"session.create\": Effect.fnUntraced(function* ({ title, directory, hostDir, sandbox, runtime }) {\n\t\t\t\tconst selection =\n\t\t\t\t\tsandbox === undefined ? undefined : yield* exported(\"Server.session.create\", Sandbox.resolve(sandbox));\n\t\t\t\tconst selected = selection?.info;\n\t\t\t\tconst handle = yield* Session.create({\n\t\t\t\t\t...(title === undefined ? {} : { title }),\n\t\t\t\t\t...(directory === undefined ? {} : { directory }),\n\t\t\t\t\t// Passed through as given, never defaulted to the server's own directory: a\n\t\t\t\t\t// session the client did not place has no project, which is a normal state.\n\t\t\t\t\t...(hostDir === undefined ? {} : { hostDir }),\n\t\t\t\t\t...(selected === undefined ? {} : { sandbox: selected }),\n\t\t\t\t\t...runtimeInput(runtime),\n\t\t\t\t}).pipe(Effect.onError(() => releaseOnFailure(selection)));\n\t\t\t\treturn toSessionInfo(yield* handle.info);\n\t\t\t}),\n\t\t\t\"plugin.reload\": Effect.fnUntraced(function* () {\n\t\t\t\treturn yield* state.reload;\n\t\t\t}),\n\t\t\t\"session.list\": Effect.fnUntraced(function* () {\n\t\t\t\tconst rows = yield* sessions.list();\n\t\t\t\treturn yield* Effect.forEach(rows, (row) => sessionInfo(row.id).pipe(Effect.orDie));\n\t\t\t}),\n\t\t\t\"session.configure\": Effect.fnUntraced(function* ({ sessionId, runtime }) {\n\t\t\t\tconst handle = yield* Session.attach({ sessionId, ...runtimeInput(runtime) });\n\t\t\t\treturn toSessionInfo(yield* handle.info);\n\t\t\t}),\n\t\t\t\"session.info\": Effect.fnUntraced(function* ({ sessionId }) {\n\t\t\t\treturn yield* sessionInfo(sessionId);\n\t\t\t}),\n\t\t\t\"session.link\": Effect.fnUntraced(function* ({ sessionId, hostDir }) {\n\t\t\t\tconst handle = yield* Session.link({ sessionId, hostDir: hostDir ?? null });\n\t\t\t\treturn toSessionInfo(yield* handle.info);\n\t\t\t}),\n\t\t\t\"session.relink\": Effect.fnUntraced(function* ({ sessionId, sandbox, directory }) {\n\t\t\t\tconst selection =\n\t\t\t\t\tsandbox === undefined ? undefined : yield* exported(\"Server.session.relink\", Sandbox.resolve(sandbox));\n\t\t\t\tconst selected = selection?.info;\n\t\t\t\tconst handle = yield* Session.relink({\n\t\t\t\t\tsessionId,\n\t\t\t\t\t...(selected === undefined ? {} : { sandbox: selected }),\n\t\t\t\t\t...(directory === undefined ? {} : { directory }),\n\t\t\t\t}).pipe(Effect.onError(() => releaseOnFailure(selection)));\n\t\t\t\treturn toSessionInfo(yield* handle.info);\n\t\t\t}),\n\t\t\t\"session.prompt\": Effect.fnUntraced(function* ({ sessionId, text, delivery, id }) {\n\t\t\t\tyield* control.prompt({\n\t\t\t\t\tsessionId,\n\t\t\t\t\tprompt: PromptSchema.Prompt.fromText(text),\n\t\t\t\t\t...(delivery === undefined ? {} : { delivery }),\n\t\t\t\t\t...(id === undefined ? {} : { id }),\n\t\t\t\t});\n\t\t\t}),\n\t\t\t\"session.interrupt\": Effect.fnUntraced(function* ({ sessionId }) {\n\t\t\t\t// Ack only: the wire answers \"was there work to stop\", and the caller\n\t\t\t\t// uses `session.wait` when it needs cleanup to have finished.\n\t\t\t\treturn { interrupted: yield* control.interrupt(sessionId, { reason: \"user\" }) };\n\t\t\t}),\n\t\t\t\"session.message\": Effect.fnUntraced(function* ({ sessionId, messageId }) {\n\t\t\t\tconst found = yield* sessions.entry(messageId);\n\t\t\t\t// Scoped to the session the caller named: an entry id is global, and a\n\t\t\t\t// client should not learn about conversations it did not ask for.\n\t\t\t\treturn { found: Option.isSome(found) && found.value.entry.sessionId === sessionId };\n\t\t\t}),\n\t\t\t\"session.wait\": Effect.fnUntraced(function* ({ sessionId }) {\n\t\t\t\tyield* control.wait(sessionId);\n\t\t\t}),\n\t\t\t\"sandbox.drivers\": Effect.fnUntraced(function* () {\n\t\t\t\tconst drivers = yield* Sandbox.drivers();\n\t\t\t\treturn drivers.map(({ name, kind }) => ({ name, kind }));\n\t\t\t}),\n\t\t\t\"sandbox.list\": Effect.fnUntraced(function* () {\n\t\t\t\treturn (yield* Sandbox.list()).map(toSandboxInfo);\n\t\t\t}),\n\t\t\t\"sandbox.create\": Effect.fnUntraced(function* ({ driver }) {\n\t\t\t\treturn toSandboxInfo(yield* exported(\"Server.sandbox.create\", Sandbox.create({ driver })));\n\t\t\t}),\n\t\t\t\"sandbox.register\": Effect.fnUntraced(function* ({ driver, providerResourceId }) {\n\t\t\t\treturn toSandboxInfo(yield* Sandbox.register({ driver, providerResourceId }));\n\t\t\t}),\n\t\t\t\"sandbox.stop\": Effect.fnUntraced(function* ({ sandboxId }) {\n\t\t\t\tyield* Sandbox.stop(sandboxId);\n\t\t\t}),\n\t\t\t// Acquiring the feed subscription is the readiness barrier: `server.connected`\n\t\t\t// is only emitted once this client is registered, so a prompt admitted after\n\t\t\t// it cannot land in the gap.\n\t\t\t\"event.subscribe\": () =>\n\t\t\t\tStream.unwrap(\n\t\t\t\t\tfeed.subscribe.pipe(\n\t\t\t\t\t\tEffect.map((events) =>\n\t\t\t\t\t\t\tStream.make({ id: EventSchema.ID.create(), type: Envelope.Connected.type, data: {} }).pipe(\n\t\t\t\t\t\t\t\tStream.concat(events),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t});\n\t}),\n);\n\nexport * as Handlers from \"./handlers.ts\";\n","import { Control, Global, Harness, Sandbox } from \"@codeworksh/harness/effect\";\nimport { NodeHttpServer } from \"@effect/platform-node\";\nimport { Effect, Layer } from \"effect\";\nimport { HttpRouter, HttpServer } from \"effect/http\";\nimport * as NetAddress from \"effect/net/NetAddress\";\nimport { RpcSerialization, RpcServer } from \"effect/rpc\";\n/* @effect-diagnostics nodeBuiltinImport:off -- the RPC listener needs a raw node server. */\nimport { createServer } from \"node:http\";\nimport { Contract } from \"./contract.ts\";\nimport { EventFeed } from \"./feed.ts\";\nimport { Handlers } from \"./handlers.ts\";\nimport { Identity } from \"./identity.ts\";\nimport { OAuth } from \"./oauth.ts\";\nimport { Registration } from \"./registration.ts\";\n\n// Managed instances outlive any single RPC; the serve scope is what stops them.\nconst managedShutdown = Layer.unwrap(\n\tEffect.gen(function* () {\n\t\tconst control = yield* Control.Service;\n\t\tyield* Effect.addFinalizer(() =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\t// Release drain leases before stopping the server's managed sandboxes.\n\t\t\t\t// Both phases are best effort and bounded so a provider cannot prevent\n\t\t\t\t// process shutdown; an interrupted stop is persisted as faulted and can\n\t\t\t\t// recover the next time that sandbox is mounted.\n\t\t\t\tyield* Effect.forEach(\n\t\t\t\t\tyield* control.active,\n\t\t\t\t\t(id) =>\n\t\t\t\t\t\tcontrol\n\t\t\t\t\t\t\t.interrupt(id, { reason: \"shutdown\", awaitSettlement: true })\n\t\t\t\t\t\t\t.pipe(Effect.timeout(\"10 seconds\"), Effect.ignore),\n\t\t\t\t\t{ concurrency: \"unbounded\", discard: true },\n\t\t\t\t);\n\t\t\t\tconst infos = yield* Sandbox.list();\n\t\t\t\tyield* Effect.forEach(\n\t\t\t\t\tinfos.filter((info) => info.ownership === \"managed\"),\n\t\t\t\t\t(info) =>\n\t\t\t\t\t\tSandbox.stop(info.id).pipe(\n\t\t\t\t\t\t\tEffect.timeout(\"10 seconds\"),\n\t\t\t\t\t\t\tEffect.catchCause((cause) =>\n\t\t\t\t\t\t\t\tEffect.logError(\"Failed to stop managed sandbox during shutdown\", cause).pipe(\n\t\t\t\t\t\t\t\t\tEffect.annotateLogs({ sandboxInstanceId: info.id }),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t{ concurrency: \"unbounded\", discard: true },\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t\treturn Layer.empty;\n\t}),\n);\n\n/**\n * Advertises the listener once it has an address: logs the endpoint and files\n * the registration later invocations discover it through.\n */\nconst announce = Layer.unwrap(\n\tEffect.gen(function* () {\n\t\tconst server = yield* HttpServer.HttpServer;\n\t\tconst global = yield* Global.Service;\n\t\tconst identity = yield* Identity.Service;\n\t\t// A ws server always binds TCP; the guard keeps the logger honest if that ever changes.\n\t\tconst address = server.address;\n\t\tconst url = `${NetAddress.formatUrlUnsafe(address, \"ws\")}${Contract.path}`;\n\t\tyield* Effect.log(`codework serve listening on ${url}`);\n\t\tif (!NetAddress.isInetAddress(address)) return Layer.empty;\n\t\treturn Registration.register({\n\t\t\thome: global.home,\n\t\t\tinfo: { pid: identity.pid, version: identity.version, url, port: address.port },\n\t\t});\n\t}),\n);\n\nexport const layer = (options: { host: string; port: number; harness: Harness.Options }) => {\n\tconst rpc = RpcServer.layerHttp({ group: Contract.Api, path: Contract.path, protocol: \"websocket\" }).pipe(\n\t\tLayer.provide(Handlers.layer.pipe(Layer.provide(EventFeed.layer))),\n\t);\n\tconst app = HttpRouter.serve(rpc, { disableListenLog: true }).pipe(\n\t\tLayer.provideMerge(managedShutdown),\n\t\tLayer.provide(OAuth.layer(options.harness.home === undefined ? {} : { home: options.harness.home })),\n\t);\n\treturn app.pipe(\n\t\tLayer.provideMerge(announce),\n\t\tLayer.provideMerge(NodeHttpServer.layer(createServer, { host: options.host, port: options.port })),\n\t\tLayer.provide(RpcSerialization.layerNdjson),\n\t\tLayer.provide(Identity.layer),\n\t\tLayer.provide(Harness.layer(options.harness)),\n\t);\n};\n\nexport * as Server from \"./server.ts\";\n","import { Global } from \"@codeworksh/harness/effect\";\nimport { Effect, FileSystem, Layer, Logger } from \"effect\";\nimport { Runtime } from \"../../../framework/runtime.ts\";\nimport { Registration } from \"../../../server/registration.ts\";\nimport { Server } from \"../../../server/server.ts\";\nimport { renderError } from \"../../error.ts\";\nimport { harnessOptions } from \"../../harness.ts\";\nimport { writeError } from \"../../output.ts\";\nimport { Cmd } from \"../cmd.ts\";\n\nconst failed = Effect.sync(() => {\n\tprocess.exitCode = 1;\n});\n\nconst report = (error: unknown) => writeError(renderError(error)).pipe(Effect.andThen(failed));\n\nexport default Runtime.handler(\n\tCmd.commands.serve,\n\tEffect.fn(\"CLI.serve\", { level: \"Info\" })(function* ({ host, port, service }) {\n\t\tconst shared = yield* Cmd.spec;\n\t\tconst harness = { ...harnessOptions(shared), watchModels: true };\n\t\tconst serve = Layer.launch(Server.layer({ host, port, harness }));\n\t\tif (!service) return yield* serve.pipe(Effect.catch(report));\n\n\t\t// A background server has no terminal: its log, and the reason it stopped, go to a\n\t\t// file the CLI that started it reads back when startup fails.\n\t\tconst background = Effect.gen(function* () {\n\t\t\tconst paths = yield* Global.resolve(harness.home === undefined ? {} : { home: harness.home });\n\t\t\tconst fs = yield* FileSystem.FileSystem;\n\t\t\tyield* fs.makeDirectory(paths.log, { recursive: true });\n\t\t\tconst logger = Logger.formatSimple.pipe(Logger.toFile(Registration.log(paths.log), { flag: \"w\" }));\n\t\t\tyield* serve.pipe(\n\t\t\t\tEffect.catch((error) => Effect.logError(renderError(error).trim()).pipe(Effect.andThen(failed))),\n\t\t\t\tEffect.provide(Logger.layer([logger])),\n\t\t\t);\n\t\t});\n\t\tyield* background.pipe(Effect.catch(report));\n\t}),\n);\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { f as layer, p as make } from "./error-CzUxh0Q9.mjs";
2
- import { a as file, i as command, n as current, o as infoJson, s as log } from "./identity-KihnHS0K.mjs";
2
+ import { a as file, i as command, n as current, o as infoJson, s as log } from "./identity-BfMXCqOi.mjs";
3
3
  import { Effect, FileSystem, Layer, Option, Ref, Schedule, Schema } from "effect";
4
4
  import { Global } from "@codeworksh/harness/effect";
5
5
  import { ChildProcess, ChildProcessSpawner } from "effect/process";
@@ -219,4 +219,4 @@ const options = (shared, server) => home(shared).pipe(Effect.map((paths) => ({
219
219
  //#endregion
220
220
  export { keepAlive as a, ensure as i, options as n, stop as o, discover as r, probe as s, home as t };
221
221
 
222
- //# sourceMappingURL=service-Eeg2xnZm.mjs.map
222
+ //# sourceMappingURL=service-BnbxCw8H.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-Eeg2xnZm.mjs","names":["Client.layer","Client.make","Registration.infoJson","Health.probe","Registration.file","log","Registration.log","Registration.command"],"sources":["../../src/server/health.ts","../../src/server/discovery.ts","../../src/cli/service.ts"],"sourcesContent":["import { Effect, Layer } from \"effect\";\nimport { Client } from \"./client.ts\";\n\n/**\n * One `server.info` call, with the answer normalized to `undefined` for every\n * way a server can fail to answer: unreachable, slow, or speaking a different\n * protocol. A health check that throws where it should say \"no\" would make\n * every caller wrap it in a catch.\n */\nexport const probe = (url: string) =>\n\tEffect.gen(function* () {\n\t\tconst context = yield* Layer.build(Client.layer(url)).pipe(Effect.orElseSucceed(() => undefined));\n\t\tif (context === undefined) return undefined;\n\t\treturn yield* Effect.gen(function* () {\n\t\t\tconst rpc = yield* Client.make;\n\t\t\treturn yield* rpc[\"server.info\"]({}).pipe(Effect.timeout(\"1 second\"));\n\t\t}).pipe(\n\t\t\tEffect.provideContext(context),\n\t\t\tEffect.orElseSucceed(() => undefined),\n\t\t);\n\t}).pipe(Effect.scoped);\n\nexport * as Health from \"./health.ts\";\n","import { type Duration, Effect, FileSystem, Option, Ref, Schedule, Schema } from \"effect\";\nimport { ChildProcess, ChildProcessSpawner } from \"effect/process\";\nimport { Health } from \"./health.ts\";\nimport { Identity } from \"./identity.ts\";\nimport { Registration } from \"./registration.ts\";\n\n/** A server a client can connect to, and the process and port behind it. */\nexport interface Endpoint {\n\treadonly url: string;\n\treadonly pid: number;\n\treadonly port: number;\n}\n\n/** A managed server could not be produced, in the words the CLI prints. */\nexport class ServerStartError extends Schema.TaggedError<ServerStartError>()(\"Discovery.ServerStartError\", {\n\tmessage: Schema.String,\n}) {}\n\nexport interface Options {\n\t/** The CodeWork home whose `service.json` names the server. */\n\treadonly home: string;\n\t/** The home's log directory, where a background server writes `server.log`. */\n\treadonly log: string;\n\treadonly host: string;\n\treadonly port: number;\n\t/** Server-owned flags placed before `serve`. */\n\treadonly args: ReadonlyArray<string>;\n}\n\nconst START_TIMEOUT = \"20 seconds\";\nconst RACE_GRACE = \"2 seconds\";\nconst STOP_TIMEOUT = \"5 seconds\";\n\nconst decode = Schema.decodeUnknownEffect(Registration.infoJson);\n\nconst read = (path: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs.readFileString(path).pipe(Effect.option);\n\t\tif (Option.isNone(text)) return undefined;\n\t\treturn yield* decode(text.value).pipe(Effect.option, Effect.map(Option.getOrUndefined));\n\t});\n\nconst remove = (path: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tyield* fs.remove(path);\n\t}).pipe(Effect.ignore);\n\n/** Whether `pid` is a running process. EPERM means it exists but belongs to someone else. */\nconst alive = (pid: number) =>\n\tEffect.try({ try: () => process.kill(pid, 0), catch: (error) => (error as NodeJS.ErrnoException).code }).pipe(\n\t\tEffect.as(true),\n\t\tEffect.catch((code) => Effect.succeed(code === \"EPERM\")),\n\t);\n\n/** Whether `pid` exits within `timeout`. */\nconst exits = (pid: number, timeout: typeof STOP_TIMEOUT) =>\n\talive(pid).pipe(\n\t\tEffect.repeat({ while: (running) => running, schedule: Schedule.spaced(\"50 millis\") }),\n\t\tEffect.timeoutOption(timeout),\n\t\tEffect.map(Option.isSome),\n\t);\n\n/**\n * The registered server, with `live` set when the process answering its endpoint\n * is the one that registered. The file is a hint, never proof: a different server\n * on a reused port must not pass for it.\n */\nconst registered = (path: string) =>\n\tEffect.gen(function* () {\n\t\tconst info = yield* read(path);\n\t\tif (info === undefined) return undefined;\n\t\tconst live = yield* Health.probe(info.url);\n\t\treturn { info, live: live?.pid === info.pid ? live : undefined };\n\t});\n\nconst endpoint = (info: Registration.Info): Endpoint => ({ url: info.url, pid: info.pid, port: info.port });\n\n/** The running server registered for `home`, with the build it reports. */\nexport const discover = (home: string) =>\n\tregistered(Registration.file(home)).pipe(\n\t\tEffect.map((found) =>\n\t\t\tfound?.live === undefined ? undefined : { ...endpoint(found.info), version: found.live.version },\n\t\t),\n\t);\n\n/**\n * Stop the server registered for `home`, returning it, or undefined when none\n * answers. Only a server that confirms it is the registrant is signalled: a pid\n * on file may since have been reused by an unrelated process.\n */\nexport const stop = (home: string) =>\n\tEffect.gen(function* () {\n\t\tconst path = Registration.file(home);\n\t\tconst found = yield* registered(path);\n\t\tif (found === undefined) return undefined;\n\t\tif (found.live === undefined) {\n\t\t\tif (!(yield* alive(found.info.pid))) yield* remove(path);\n\t\t\treturn undefined;\n\t\t}\n\t\tyield* terminate(path, found.info.pid);\n\t\treturn endpoint(found.info);\n\t});\n\n/**\n * Ensure a healthy local server for `home`: reuse the registered one, replace it\n * when `replace` is set and it runs a different build, or start a background one.\n *\n * The background server is detached and outlives this caller, so the next\n * invocation reuses it. When two callers race, only the contender that binds the\n * port registers; the loser exits and both adopt the winner, because a caller\n * only ever believes a registration it can confirm over the wire.\n */\nexport const ensure = (\n\toptions: Options & {\n\t\treadonly replace: boolean;\n\t\treadonly onStart?: (reason: \"missing\" | \"version-mismatch\") => void;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst path = Registration.file(options.home);\n\t\tconst found = yield* registered(path);\n\t\tif (found?.live !== undefined) {\n\t\t\tif (!options.replace || found.live.version === Identity.current.version) return endpoint(found.info);\n\t\t\tyield* Effect.sync(() => options.onStart?.(\"version-mismatch\"));\n\t\t\tyield* terminate(path, found.info.pid);\n\t\t} else {\n\t\t\t// A file nothing answers for, left by a crash, must not mislead the next caller.\n\t\t\tif (found !== undefined && !(yield* alive(found.info.pid))) yield* remove(path);\n\t\t\tyield* Effect.sync(() => options.onStart?.(\"missing\"));\n\t\t}\n\t\treturn yield* start(path, options);\n\t});\n\n/** The registered server once it answers, polled every 200ms for up to `timeout`. */\nconst ready = (path: string, timeout: Duration.Input, pending: Effect.Effect<boolean>) =>\n\tEffect.gen(function* () {\n\t\tconst next = yield* registered(path);\n\t\tif (next?.live !== undefined) return Option.some(endpoint(next.info));\n\t\t// A live registrant that does not answer yet is another caller's server starting up.\n\t\tconst waiting = (yield* pending) || (next !== undefined && (yield* alive(next.info.pid)));\n\t\treturn waiting ? Option.none() : yield* Effect.fail(\"exited\" as const);\n\t}).pipe(\n\t\tEffect.repeat({ until: Option.isSome, schedule: Schedule.spaced(\"200 millis\") }),\n\t\tEffect.timeoutOption(timeout),\n\t\tEffect.map(Option.flatten),\n\t\tEffect.orElseSucceed(() => Option.none<Endpoint>()),\n\t);\n\n/**\n * Start a background server and wait for it to register, quoting the reason\n * from its log when it cannot.\n *\n * The contender stays tied to this scope until it is the server adopted: a\n * timeout, an interrupt, or another caller winning the race stops it rather than\n * leaving an unmanaged server behind.\n */\nconst start = (path: string, options: Options) =>\n\tEffect.gen(function* () {\n\t\tconst contender = yield* spawn(options);\n\t\tconst won = yield* ready(path, START_TIMEOUT, contender.isRunning.pipe(Effect.orElseSucceed(() => false)));\n\t\t// A contender that lost the bind race exits before the winner may have filed its\n\t\t// registration; give the winner a moment before calling the start a failure.\n\t\tconst server = Option.isSome(won) ? won : yield* ready(path, RACE_GRACE, Effect.succeed(true));\n\t\tif (Option.isSome(server)) {\n\t\t\tif (server.value.pid === contender.pid) yield* contender.unref.pipe(Effect.asVoid);\n\t\t\treturn server.value;\n\t\t}\n\n\t\tconst log = Registration.log(options.log);\n\t\tconst reason = yield* lastLine(log);\n\t\treturn yield* new ServerStartError({\n\t\t\tmessage: [\n\t\t\t\t`could not start a CodeWork server on ${options.host}:${options.port}`,\n\t\t\t\t...(reason === undefined ? [] : [`reason: ${reason}`]),\n\t\t\t\t`log: ${log}`,\n\t\t\t\t\"hint: pass --port to use another port, or point `codework tui --server` at a running server\",\n\t\t\t].join(\"\\n\"),\n\t\t});\n\t}).pipe(Effect.scoped);\n\n/**\n * Keep the session's server running for as long as the caller lives.\n *\n * The TUI only reconnects; it cannot start a server. If the one it uses goes\n * away, this brings one back on the same port so the reconnect lands. It never\n * replaces a running server: another invocation may have just upgraded it.\n */\nexport const keepAlive = (initial: Endpoint, options: Options) =>\n\tEffect.gen(function* () {\n\t\tconst current = yield* Ref.make(initial);\n\t\tyield* Effect.gen(function* () {\n\t\t\tconst server = yield* Ref.get(current);\n\t\t\tif (yield* alive(server.pid)) return;\n\t\t\tconst next = yield* ensure({ ...options, port: server.port, replace: false }).pipe(\n\t\t\t\tEffect.orElseSucceed(() => server),\n\t\t\t);\n\t\t\tyield* Ref.set(current, next);\n\t\t}).pipe(Effect.repeat(Schedule.spaced(\"1 second\")));\n\t});\n\n/** Ask `pid` to shut down, escalating to SIGKILL, and retire its registration. */\nconst terminate = (path: string, pid: number) =>\n\tEffect.gen(function* () {\n\t\tconst signal = (name: NodeJS.Signals) => Effect.try(() => process.kill(pid, name)).pipe(Effect.ignore);\n\t\tyield* signal(\"SIGTERM\");\n\t\tif (!(yield* exits(pid, STOP_TIMEOUT))) {\n\t\t\tyield* signal(\"SIGKILL\");\n\t\t\tyield* exits(pid, STOP_TIMEOUT);\n\t\t}\n\t\t// A server removes its own file on a clean exit; this covers the SIGKILL path.\n\t\tconst info = yield* read(path);\n\t\tif (info?.pid === pid) yield* remove(path);\n\t});\n\nconst lastLine = (path: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs.readFileString(path).pipe(Effect.orElseSucceed(() => \"\"));\n\t\treturn text\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => line.trim())\n\t\t\t.findLast((line) => line.length > 0);\n\t});\n\n/**\n * Spawn `codework serve --service` detached, inheriting this environment so it\n * resolves the same home, catalog and credentials. It writes its own log, so no\n * stdio is tied to this short-lived caller. It stays referenced, and so stopped\n * with the scope, until `start` adopts it.\n */\nconst spawn = (options: Options) =>\n\tEffect.gen(function* () {\n\t\tconst [file, ...base] = Registration.command();\n\t\tif (file === undefined) return yield* Effect.die(new Error(\"could not resolve the codework entrypoint\"));\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n\t\tconst handle = yield* spawner.spawn(\n\t\t\tChildProcess.make(\n\t\t\t\tfile,\n\t\t\t\t[...base, ...options.args, \"serve\", \"--service\", \"--host\", options.host, \"--port\", String(options.port)],\n\t\t\t\t{ detached: true, stdin: \"ignore\", stdout: \"ignore\", stderr: \"ignore\" },\n\t\t\t),\n\t\t);\n\t\treturn handle;\n\t});\n\nexport * as Discovery from \"./discovery.ts\";\n","import { Global } from \"@codeworksh/harness/effect\";\nimport { Effect, Option } from \"effect\";\nimport type { Discovery } from \"../server/discovery.ts\";\n\ninterface Shared {\n\treadonly userConfigDir: Option.Option<string>;\n\treadonly home: Option.Option<string>;\n\treadonly database: Option.Option<string>;\n}\n\n/** The CodeWork home the shared flags name, resolved the way the harness resolves it. */\nexport const home = (shared: Shared) => Global.resolve(Option.isSome(shared.home) ? { home: shared.home.value } : {});\n\n/**\n * How `tui` and `service` find or start the background server: the home whose\n * `service.json` names it, and the server-owned flags it is started with, in the\n * order `serve` parses them.\n */\nexport const options = (shared: Shared, server: { readonly host: string; readonly port: number }) =>\n\thome(shared).pipe(\n\t\tEffect.map((paths): Discovery.Options => ({\n\t\t\thome: paths.home,\n\t\t\tlog: paths.log,\n\t\t\t...server,\n\t\t\targs: [\n\t\t\t\t...(Option.isSome(shared.home) ? [\"--home\", shared.home.value] : []),\n\t\t\t\t...(Option.isSome(shared.database) ? [\"--database\", shared.database.value] : []),\n\t\t\t\t...(Option.isSome(shared.userConfigDir) ? [\"--user-config-dir\", shared.userConfigDir.value] : []),\n\t\t\t],\n\t\t})),\n\t);\n\nexport * as Service from \"./service.ts\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"service-BnbxCw8H.mjs","names":["Client.layer","Client.make","Registration.infoJson","Health.probe","Registration.file","log","Registration.log","Registration.command"],"sources":["../../src/server/health.ts","../../src/server/discovery.ts","../../src/cli/service.ts"],"sourcesContent":["import { Effect, Layer } from \"effect\";\nimport { Client } from \"./client.ts\";\n\n/**\n * One `server.info` call, with the answer normalized to `undefined` for every\n * way a server can fail to answer: unreachable, slow, or speaking a different\n * protocol. A health check that throws where it should say \"no\" would make\n * every caller wrap it in a catch.\n */\nexport const probe = (url: string) =>\n\tEffect.gen(function* () {\n\t\tconst context = yield* Layer.build(Client.layer(url)).pipe(Effect.orElseSucceed(() => undefined));\n\t\tif (context === undefined) return undefined;\n\t\treturn yield* Effect.gen(function* () {\n\t\t\tconst rpc = yield* Client.make;\n\t\t\treturn yield* rpc[\"server.info\"]({}).pipe(Effect.timeout(\"1 second\"));\n\t\t}).pipe(\n\t\t\tEffect.provideContext(context),\n\t\t\tEffect.orElseSucceed(() => undefined),\n\t\t);\n\t}).pipe(Effect.scoped);\n\nexport * as Health from \"./health.ts\";\n","import { type Duration, Effect, FileSystem, Option, Ref, Schedule, Schema } from \"effect\";\nimport { ChildProcess, ChildProcessSpawner } from \"effect/process\";\nimport { Health } from \"./health.ts\";\nimport { Identity } from \"./identity.ts\";\nimport { Registration } from \"./registration.ts\";\n\n/** A server a client can connect to, and the process and port behind it. */\nexport interface Endpoint {\n\treadonly url: string;\n\treadonly pid: number;\n\treadonly port: number;\n}\n\n/** A managed server could not be produced, in the words the CLI prints. */\nexport class ServerStartError extends Schema.TaggedError<ServerStartError>()(\"Discovery.ServerStartError\", {\n\tmessage: Schema.String,\n}) {}\n\nexport interface Options {\n\t/** The CodeWork home whose `service.json` names the server. */\n\treadonly home: string;\n\t/** The home's log directory, where a background server writes `server.log`. */\n\treadonly log: string;\n\treadonly host: string;\n\treadonly port: number;\n\t/** Server-owned flags placed before `serve`. */\n\treadonly args: ReadonlyArray<string>;\n}\n\nconst START_TIMEOUT = \"20 seconds\";\nconst RACE_GRACE = \"2 seconds\";\nconst STOP_TIMEOUT = \"5 seconds\";\n\nconst decode = Schema.decodeUnknownEffect(Registration.infoJson);\n\nconst read = (path: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs.readFileString(path).pipe(Effect.option);\n\t\tif (Option.isNone(text)) return undefined;\n\t\treturn yield* decode(text.value).pipe(Effect.option, Effect.map(Option.getOrUndefined));\n\t});\n\nconst remove = (path: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tyield* fs.remove(path);\n\t}).pipe(Effect.ignore);\n\n/** Whether `pid` is a running process. EPERM means it exists but belongs to someone else. */\nconst alive = (pid: number) =>\n\tEffect.try({ try: () => process.kill(pid, 0), catch: (error) => (error as NodeJS.ErrnoException).code }).pipe(\n\t\tEffect.as(true),\n\t\tEffect.catch((code) => Effect.succeed(code === \"EPERM\")),\n\t);\n\n/** Whether `pid` exits within `timeout`. */\nconst exits = (pid: number, timeout: typeof STOP_TIMEOUT) =>\n\talive(pid).pipe(\n\t\tEffect.repeat({ while: (running) => running, schedule: Schedule.spaced(\"50 millis\") }),\n\t\tEffect.timeoutOption(timeout),\n\t\tEffect.map(Option.isSome),\n\t);\n\n/**\n * The registered server, with `live` set when the process answering its endpoint\n * is the one that registered. The file is a hint, never proof: a different server\n * on a reused port must not pass for it.\n */\nconst registered = (path: string) =>\n\tEffect.gen(function* () {\n\t\tconst info = yield* read(path);\n\t\tif (info === undefined) return undefined;\n\t\tconst live = yield* Health.probe(info.url);\n\t\treturn { info, live: live?.pid === info.pid ? live : undefined };\n\t});\n\nconst endpoint = (info: Registration.Info): Endpoint => ({ url: info.url, pid: info.pid, port: info.port });\n\n/** The running server registered for `home`, with the build it reports. */\nexport const discover = (home: string) =>\n\tregistered(Registration.file(home)).pipe(\n\t\tEffect.map((found) =>\n\t\t\tfound?.live === undefined ? undefined : { ...endpoint(found.info), version: found.live.version },\n\t\t),\n\t);\n\n/**\n * Stop the server registered for `home`, returning it, or undefined when none\n * answers. Only a server that confirms it is the registrant is signalled: a pid\n * on file may since have been reused by an unrelated process.\n */\nexport const stop = (home: string) =>\n\tEffect.gen(function* () {\n\t\tconst path = Registration.file(home);\n\t\tconst found = yield* registered(path);\n\t\tif (found === undefined) return undefined;\n\t\tif (found.live === undefined) {\n\t\t\tif (!(yield* alive(found.info.pid))) yield* remove(path);\n\t\t\treturn undefined;\n\t\t}\n\t\tyield* terminate(path, found.info.pid);\n\t\treturn endpoint(found.info);\n\t});\n\n/**\n * Ensure a healthy local server for `home`: reuse the registered one, replace it\n * when `replace` is set and it runs a different build, or start a background one.\n *\n * The background server is detached and outlives this caller, so the next\n * invocation reuses it. When two callers race, only the contender that binds the\n * port registers; the loser exits and both adopt the winner, because a caller\n * only ever believes a registration it can confirm over the wire.\n */\nexport const ensure = (\n\toptions: Options & {\n\t\treadonly replace: boolean;\n\t\treadonly onStart?: (reason: \"missing\" | \"version-mismatch\") => void;\n\t},\n) =>\n\tEffect.gen(function* () {\n\t\tconst path = Registration.file(options.home);\n\t\tconst found = yield* registered(path);\n\t\tif (found?.live !== undefined) {\n\t\t\tif (!options.replace || found.live.version === Identity.current.version) return endpoint(found.info);\n\t\t\tyield* Effect.sync(() => options.onStart?.(\"version-mismatch\"));\n\t\t\tyield* terminate(path, found.info.pid);\n\t\t} else {\n\t\t\t// A file nothing answers for, left by a crash, must not mislead the next caller.\n\t\t\tif (found !== undefined && !(yield* alive(found.info.pid))) yield* remove(path);\n\t\t\tyield* Effect.sync(() => options.onStart?.(\"missing\"));\n\t\t}\n\t\treturn yield* start(path, options);\n\t});\n\n/** The registered server once it answers, polled every 200ms for up to `timeout`. */\nconst ready = (path: string, timeout: Duration.Input, pending: Effect.Effect<boolean>) =>\n\tEffect.gen(function* () {\n\t\tconst next = yield* registered(path);\n\t\tif (next?.live !== undefined) return Option.some(endpoint(next.info));\n\t\t// A live registrant that does not answer yet is another caller's server starting up.\n\t\tconst waiting = (yield* pending) || (next !== undefined && (yield* alive(next.info.pid)));\n\t\treturn waiting ? Option.none() : yield* Effect.fail(\"exited\" as const);\n\t}).pipe(\n\t\tEffect.repeat({ until: Option.isSome, schedule: Schedule.spaced(\"200 millis\") }),\n\t\tEffect.timeoutOption(timeout),\n\t\tEffect.map(Option.flatten),\n\t\tEffect.orElseSucceed(() => Option.none<Endpoint>()),\n\t);\n\n/**\n * Start a background server and wait for it to register, quoting the reason\n * from its log when it cannot.\n *\n * The contender stays tied to this scope until it is the server adopted: a\n * timeout, an interrupt, or another caller winning the race stops it rather than\n * leaving an unmanaged server behind.\n */\nconst start = (path: string, options: Options) =>\n\tEffect.gen(function* () {\n\t\tconst contender = yield* spawn(options);\n\t\tconst won = yield* ready(path, START_TIMEOUT, contender.isRunning.pipe(Effect.orElseSucceed(() => false)));\n\t\t// A contender that lost the bind race exits before the winner may have filed its\n\t\t// registration; give the winner a moment before calling the start a failure.\n\t\tconst server = Option.isSome(won) ? won : yield* ready(path, RACE_GRACE, Effect.succeed(true));\n\t\tif (Option.isSome(server)) {\n\t\t\tif (server.value.pid === contender.pid) yield* contender.unref.pipe(Effect.asVoid);\n\t\t\treturn server.value;\n\t\t}\n\n\t\tconst log = Registration.log(options.log);\n\t\tconst reason = yield* lastLine(log);\n\t\treturn yield* new ServerStartError({\n\t\t\tmessage: [\n\t\t\t\t`could not start a CodeWork server on ${options.host}:${options.port}`,\n\t\t\t\t...(reason === undefined ? [] : [`reason: ${reason}`]),\n\t\t\t\t`log: ${log}`,\n\t\t\t\t\"hint: pass --port to use another port, or point `codework tui --server` at a running server\",\n\t\t\t].join(\"\\n\"),\n\t\t});\n\t}).pipe(Effect.scoped);\n\n/**\n * Keep the session's server running for as long as the caller lives.\n *\n * The TUI only reconnects; it cannot start a server. If the one it uses goes\n * away, this brings one back on the same port so the reconnect lands. It never\n * replaces a running server: another invocation may have just upgraded it.\n */\nexport const keepAlive = (initial: Endpoint, options: Options) =>\n\tEffect.gen(function* () {\n\t\tconst current = yield* Ref.make(initial);\n\t\tyield* Effect.gen(function* () {\n\t\t\tconst server = yield* Ref.get(current);\n\t\t\tif (yield* alive(server.pid)) return;\n\t\t\tconst next = yield* ensure({ ...options, port: server.port, replace: false }).pipe(\n\t\t\t\tEffect.orElseSucceed(() => server),\n\t\t\t);\n\t\t\tyield* Ref.set(current, next);\n\t\t}).pipe(Effect.repeat(Schedule.spaced(\"1 second\")));\n\t});\n\n/** Ask `pid` to shut down, escalating to SIGKILL, and retire its registration. */\nconst terminate = (path: string, pid: number) =>\n\tEffect.gen(function* () {\n\t\tconst signal = (name: NodeJS.Signals) => Effect.try(() => process.kill(pid, name)).pipe(Effect.ignore);\n\t\tyield* signal(\"SIGTERM\");\n\t\tif (!(yield* exits(pid, STOP_TIMEOUT))) {\n\t\t\tyield* signal(\"SIGKILL\");\n\t\t\tyield* exits(pid, STOP_TIMEOUT);\n\t\t}\n\t\t// A server removes its own file on a clean exit; this covers the SIGKILL path.\n\t\tconst info = yield* read(path);\n\t\tif (info?.pid === pid) yield* remove(path);\n\t});\n\nconst lastLine = (path: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem;\n\t\tconst text = yield* fs.readFileString(path).pipe(Effect.orElseSucceed(() => \"\"));\n\t\treturn text\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => line.trim())\n\t\t\t.findLast((line) => line.length > 0);\n\t});\n\n/**\n * Spawn `codework serve --service` detached, inheriting this environment so it\n * resolves the same home, catalog and credentials. It writes its own log, so no\n * stdio is tied to this short-lived caller. It stays referenced, and so stopped\n * with the scope, until `start` adopts it.\n */\nconst spawn = (options: Options) =>\n\tEffect.gen(function* () {\n\t\tconst [file, ...base] = Registration.command();\n\t\tif (file === undefined) return yield* Effect.die(new Error(\"could not resolve the codework entrypoint\"));\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n\t\tconst handle = yield* spawner.spawn(\n\t\t\tChildProcess.make(\n\t\t\t\tfile,\n\t\t\t\t[...base, ...options.args, \"serve\", \"--service\", \"--host\", options.host, \"--port\", String(options.port)],\n\t\t\t\t{ detached: true, stdin: \"ignore\", stdout: \"ignore\", stderr: \"ignore\" },\n\t\t\t),\n\t\t);\n\t\treturn handle;\n\t});\n\nexport * as Discovery from \"./discovery.ts\";\n","import { Global } from \"@codeworksh/harness/effect\";\nimport { Effect, Option } from \"effect\";\nimport type { Discovery } from \"../server/discovery.ts\";\n\ninterface Shared {\n\treadonly userConfigDir: Option.Option<string>;\n\treadonly home: Option.Option<string>;\n\treadonly database: Option.Option<string>;\n}\n\n/** The CodeWork home the shared flags name, resolved the way the harness resolves it. */\nexport const home = (shared: Shared) => Global.resolve(Option.isSome(shared.home) ? { home: shared.home.value } : {});\n\n/**\n * How `tui` and `service` find or start the background server: the home whose\n * `service.json` names it, and the server-owned flags it is started with, in the\n * order `serve` parses them.\n */\nexport const options = (shared: Shared, server: { readonly host: string; readonly port: number }) =>\n\thome(shared).pipe(\n\t\tEffect.map((paths): Discovery.Options => ({\n\t\t\thome: paths.home,\n\t\t\tlog: paths.log,\n\t\t\t...server,\n\t\t\targs: [\n\t\t\t\t...(Option.isSome(shared.home) ? [\"--home\", shared.home.value] : []),\n\t\t\t\t...(Option.isSome(shared.database) ? [\"--database\", shared.database.value] : []),\n\t\t\t\t...(Option.isSome(shared.userConfigDir) ? [\"--user-config-dir\", shared.userConfigDir.value] : []),\n\t\t\t],\n\t\t})),\n\t);\n\nexport * as Service from \"./service.ts\";\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { i as Cmd } from "./runtime-CIBm_3RX.mjs";
1
+ import { i as Cmd } from "./runtime-B43doHjV.mjs";
2
2
  import { f as layer, n as OAuthError, t as InvalidInputError } from "./error-CzUxh0Q9.mjs";
3
3
  import { Effect, Option, Path } from "effect";
4
4
  import { Global } from "@codeworksh/harness/effect";
@@ -113,4 +113,4 @@ const withServer = (url, program) => program.pipe(Effect.provide(layer(url)), Ef
113
113
  //#endregion
114
114
  export { oauthProviderLabel as a, makeOps as i, attempt as n, selectProvider as o, localOps as r, withServer as s, assertServerScope as t };
115
115
 
116
- //# sourceMappingURL=shared-DjyUhNsi.mjs.map
116
+ //# sourceMappingURL=shared-wNZoC017.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-DjyUhNsi.mjs","names":["Client.layer"],"sources":["../../src/cli/cmd/handlers/auth/shared.ts"],"sourcesContent":["/* @effect-diagnostics nodeBuiltinImport:off -- OAuth login opens the system browser. */\n/* @effect-diagnostics globalDate:off -- Stored expiry timestamps are rendered for the user. */\n/* oxlint-disable effecttsgo/async-function -- Aikit OAuth callbacks require Promise-returning functions. */\nimport {\n\tGitHubCopilotOAuthClient,\n\tJsonGitHubCopilotAuthStorage,\n\ttype GitHubCopilotAuthStorage,\n} from \"@codeworksh/aikit/oauth/github/copilot\";\nimport {\n\tJsonOpenAICodexAuthStorage,\n\tOpenAICodexOAuthClient,\n\ttype OpenAICodexAuthStorage,\n} from \"@codeworksh/aikit/oauth/openai/codex\";\nimport { openBrowser, promptLine } from \"@codeworksh/aikit/oauth/interactive\";\nimport {\n\tcheckOAuthProvider,\n\toauthProviderLabel,\n\tsummarizeGitHubCopilot,\n\tsummarizeOpenAICodex,\n\ttype OAuthSummary,\n} from \"@codeworksh/aikit/oauth/summary\";\nimport { Global } from \"@codeworksh/harness/effect\";\nimport { Effect, Option, Path } from \"effect\";\nimport { Client } from \"../../../../server/client.ts\";\nimport type { Contract } from \"../../../../server/contract.ts\";\nimport { InvalidInputError, OAuthError } from \"../../../error.ts\";\nimport { Cmd } from \"../../cmd.ts\";\n\nexport type Provider = Contract.OAuthProvider;\n\n// The wire shape and aikit's summary are the same record.\nexport type Summary = Contract.OAuthInfo & OAuthSummary;\n\nconst announce = (\n\tinfo: { url: string; userCode?: string | undefined; instructions?: string | undefined },\n\tbrowser: boolean,\n): void => {\n\tprocess.stderr.write(\n\t\t`${info.instructions ?? \"Complete authentication in your browser.\"}\\n${\n\t\t\tinfo.userCode === undefined ? \"\" : `Enter code: ${info.userCode}\\n`\n\t\t}${info.url}\\n`,\n\t);\n\tif (browser) {\n\t\tvoid openBrowser(info.url, (error) => void process.stderr.write(`Failed to open browser: ${error.message}\\n`));\n\t}\n};\n\nexport interface LoginOptions {\n\treadonly browser: boolean;\n\treadonly device: boolean;\n\treadonly enterprise: Option.Option<string>;\n\treadonly enableModels: boolean;\n}\n\nexport interface Ops {\n\treadonly path: string;\n\treadonly login: (options: LoginOptions) => Promise<{ wire: Contract.OAuthCredentials; summary: Summary }>;\n\treadonly stored: () => Promise<Summary | undefined>;\n\treadonly refreshed: () => Promise<Summary | undefined>;\n\treadonly logout: () => Promise<void>;\n}\n\n/** Holds nothing: a server's credentials live on the server, not on this disk. */\nconst transient: OpenAICodexAuthStorage & GitHubCopilotAuthStorage = {\n\tget: async () => undefined,\n\tset: async () => {},\n\tclear: async () => {},\n};\n\nconst codexOps = (storage: OpenAICodexAuthStorage, path: string): Ops => {\n\tconst client = new OpenAICodexOAuthClient({ storage });\n\treturn {\n\t\tpath,\n\t\tlogin: async (options) => {\n\t\t\tconst credentials = await client.login({\n\t\t\t\tdevice: options.device,\n\t\t\t\tonAuth: (info) => announce(info, options.browser),\n\t\t\t\tonProgress: (message) => void process.stderr.write(`${message}\\n`),\n\t\t\t\tonPrompt: (prompt) => promptLine(prompt.message),\n\t\t\t});\n\t\t\treturn { wire: { provider: \"openai-codex\", ...credentials }, summary: summarizeOpenAICodex(credentials) };\n\t\t},\n\t\tstored: async () => {\n\t\t\tconst credentials = await storage.get();\n\t\t\treturn credentials && summarizeOpenAICodex(credentials);\n\t\t},\n\t\trefreshed: async () => {\n\t\t\tconst credentials = await client.getCredentials();\n\t\t\treturn credentials && summarizeOpenAICodex(credentials);\n\t\t},\n\t\tlogout: () => client.logout(),\n\t};\n};\n\nconst copilotOps = (storage: GitHubCopilotAuthStorage, path: string): Ops => {\n\tconst client = new GitHubCopilotOAuthClient({ storage });\n\tconst read = async () => {\n\t\tconst credentials = await storage.get();\n\t\treturn credentials && summarizeGitHubCopilot(credentials);\n\t};\n\treturn {\n\t\tpath,\n\t\tlogin: async (options) => {\n\t\t\tconst credentials = await client.login({\n\t\t\t\t...(Option.isSome(options.enterprise) && { enterpriseUrl: options.enterprise.value }),\n\t\t\t\tenableModels: options.enableModels,\n\t\t\t\tonAuth: (info) => announce(info, options.browser),\n\t\t\t\tonProgress: (message) => void process.stderr.write(`${message}\\n`),\n\t\t\t});\n\t\t\treturn { wire: { provider: \"github-copilot\", ...credentials }, summary: summarizeGitHubCopilot(credentials) };\n\t\t},\n\t\tstored: read,\n\t\t// GitHub OAuth tokens never expire, so there is nothing to refresh.\n\t\trefreshed: read,\n\t\tlogout: () => client.logout(),\n\t};\n};\n\nexport const makeOps = (provider: Provider, options: { path?: string | undefined; persist?: boolean } = {}): Ops => {\n\tconst file = options.path === undefined ? {} : { path: options.path };\n\tif (provider === \"openai-codex\") {\n\t\tconst storage = options.persist === false ? undefined : new JsonOpenAICodexAuthStorage(file);\n\t\treturn codexOps(storage ?? transient, storage?.path ?? \"\");\n\t}\n\tconst storage = options.persist === false ? undefined : new JsonGitHubCopilotAuthStorage(file);\n\treturn copilotOps(storage ?? transient, storage?.path ?? \"\");\n};\n\nexport const attempt = <A>(message: string, run: () => Promise<A>) =>\n\tEffect.tryPromise({ try: run, catch: (cause) => new OAuthError({ message, cause }) });\n\n/** The provider named by the two mutually exclusive flags. */\nexport const selectProvider = (flags: {\n\treadonly openaiCodex: boolean;\n\treadonly githubCopilot: boolean;\n}): Effect.Effect<Provider, InvalidInputError> => {\n\tconst checked = checkOAuthProvider(flags);\n\treturn checked.ok\n\t\t? Effect.succeed(checked.provider)\n\t\t: Effect.fail(new InvalidInputError({ message: checked.message }));\n};\n\n/** Reject the local-credential flags when the credentials live on a server. */\nexport const assertServerScope = (authFile: Option.Option<string>) =>\n\tEffect.gen(function* () {\n\t\tconst shared = yield* Cmd.spec;\n\t\tif (Option.isSome(authFile) || Option.isSome(shared.home)) {\n\t\t\treturn yield* new InvalidInputError({\n\t\t\t\tmessage: \"--auth-file and --home belong on codework serve when using --server\",\n\t\t\t});\n\t\t}\n\t});\n\n/** Credential operations against this machine's auth.json. */\nexport const localOps = (provider: Provider, authFile: Option.Option<string>) =>\n\tEffect.gen(function* () {\n\t\tconst shared = yield* Cmd.spec;\n\t\tconst path = yield* Path.Path;\n\t\tconst file = Option.isSome(authFile)\n\t\t\t? authFile.value\n\t\t\t: Option.isSome(shared.home)\n\t\t\t\t? path.join((yield* Global.resolve({ home: shared.home.value })).home, \"aikit\", \"auth.json\")\n\t\t\t\t: undefined;\n\t\treturn makeOps(provider, file === undefined ? {} : { path: file });\n\t});\n\n/** Run an effect against the RPC server at `url`, discharging the client. */\nexport const withServer = <A, E, R>(url: string, program: Effect.Effect<A, E, R>) =>\n\tprogram.pipe(Effect.provide(Client.layer(url)), Effect.scoped);\n\nexport { Client, oauthProviderLabel };\n"],"mappings":"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"}
1
+ {"version":3,"file":"shared-wNZoC017.mjs","names":["Client.layer"],"sources":["../../src/cli/cmd/handlers/auth/shared.ts"],"sourcesContent":["/* @effect-diagnostics nodeBuiltinImport:off -- OAuth login opens the system browser. */\n/* @effect-diagnostics globalDate:off -- Stored expiry timestamps are rendered for the user. */\n/* oxlint-disable effecttsgo/async-function -- Aikit OAuth callbacks require Promise-returning functions. */\nimport {\n\tGitHubCopilotOAuthClient,\n\tJsonGitHubCopilotAuthStorage,\n\ttype GitHubCopilotAuthStorage,\n} from \"@codeworksh/aikit/oauth/github/copilot\";\nimport {\n\tJsonOpenAICodexAuthStorage,\n\tOpenAICodexOAuthClient,\n\ttype OpenAICodexAuthStorage,\n} from \"@codeworksh/aikit/oauth/openai/codex\";\nimport { openBrowser, promptLine } from \"@codeworksh/aikit/oauth/interactive\";\nimport {\n\tcheckOAuthProvider,\n\toauthProviderLabel,\n\tsummarizeGitHubCopilot,\n\tsummarizeOpenAICodex,\n\ttype OAuthSummary,\n} from \"@codeworksh/aikit/oauth/summary\";\nimport { Global } from \"@codeworksh/harness/effect\";\nimport { Effect, Option, Path } from \"effect\";\nimport { Client } from \"../../../../server/client.ts\";\nimport type { Contract } from \"../../../../server/contract.ts\";\nimport { InvalidInputError, OAuthError } from \"../../../error.ts\";\nimport { Cmd } from \"../../cmd.ts\";\n\nexport type Provider = Contract.OAuthProvider;\n\n// The wire shape and aikit's summary are the same record.\nexport type Summary = Contract.OAuthInfo & OAuthSummary;\n\nconst announce = (\n\tinfo: { url: string; userCode?: string | undefined; instructions?: string | undefined },\n\tbrowser: boolean,\n): void => {\n\tprocess.stderr.write(\n\t\t`${info.instructions ?? \"Complete authentication in your browser.\"}\\n${\n\t\t\tinfo.userCode === undefined ? \"\" : `Enter code: ${info.userCode}\\n`\n\t\t}${info.url}\\n`,\n\t);\n\tif (browser) {\n\t\tvoid openBrowser(info.url, (error) => void process.stderr.write(`Failed to open browser: ${error.message}\\n`));\n\t}\n};\n\nexport interface LoginOptions {\n\treadonly browser: boolean;\n\treadonly device: boolean;\n\treadonly enterprise: Option.Option<string>;\n\treadonly enableModels: boolean;\n}\n\nexport interface Ops {\n\treadonly path: string;\n\treadonly login: (options: LoginOptions) => Promise<{ wire: Contract.OAuthCredentials; summary: Summary }>;\n\treadonly stored: () => Promise<Summary | undefined>;\n\treadonly refreshed: () => Promise<Summary | undefined>;\n\treadonly logout: () => Promise<void>;\n}\n\n/** Holds nothing: a server's credentials live on the server, not on this disk. */\nconst transient: OpenAICodexAuthStorage & GitHubCopilotAuthStorage = {\n\tget: async () => undefined,\n\tset: async () => {},\n\tclear: async () => {},\n};\n\nconst codexOps = (storage: OpenAICodexAuthStorage, path: string): Ops => {\n\tconst client = new OpenAICodexOAuthClient({ storage });\n\treturn {\n\t\tpath,\n\t\tlogin: async (options) => {\n\t\t\tconst credentials = await client.login({\n\t\t\t\tdevice: options.device,\n\t\t\t\tonAuth: (info) => announce(info, options.browser),\n\t\t\t\tonProgress: (message) => void process.stderr.write(`${message}\\n`),\n\t\t\t\tonPrompt: (prompt) => promptLine(prompt.message),\n\t\t\t});\n\t\t\treturn { wire: { provider: \"openai-codex\", ...credentials }, summary: summarizeOpenAICodex(credentials) };\n\t\t},\n\t\tstored: async () => {\n\t\t\tconst credentials = await storage.get();\n\t\t\treturn credentials && summarizeOpenAICodex(credentials);\n\t\t},\n\t\trefreshed: async () => {\n\t\t\tconst credentials = await client.getCredentials();\n\t\t\treturn credentials && summarizeOpenAICodex(credentials);\n\t\t},\n\t\tlogout: () => client.logout(),\n\t};\n};\n\nconst copilotOps = (storage: GitHubCopilotAuthStorage, path: string): Ops => {\n\tconst client = new GitHubCopilotOAuthClient({ storage });\n\tconst read = async () => {\n\t\tconst credentials = await storage.get();\n\t\treturn credentials && summarizeGitHubCopilot(credentials);\n\t};\n\treturn {\n\t\tpath,\n\t\tlogin: async (options) => {\n\t\t\tconst credentials = await client.login({\n\t\t\t\t...(Option.isSome(options.enterprise) && { enterpriseUrl: options.enterprise.value }),\n\t\t\t\tenableModels: options.enableModels,\n\t\t\t\tonAuth: (info) => announce(info, options.browser),\n\t\t\t\tonProgress: (message) => void process.stderr.write(`${message}\\n`),\n\t\t\t});\n\t\t\treturn { wire: { provider: \"github-copilot\", ...credentials }, summary: summarizeGitHubCopilot(credentials) };\n\t\t},\n\t\tstored: read,\n\t\t// GitHub OAuth tokens never expire, so there is nothing to refresh.\n\t\trefreshed: read,\n\t\tlogout: () => client.logout(),\n\t};\n};\n\nexport const makeOps = (provider: Provider, options: { path?: string | undefined; persist?: boolean } = {}): Ops => {\n\tconst file = options.path === undefined ? {} : { path: options.path };\n\tif (provider === \"openai-codex\") {\n\t\tconst storage = options.persist === false ? undefined : new JsonOpenAICodexAuthStorage(file);\n\t\treturn codexOps(storage ?? transient, storage?.path ?? \"\");\n\t}\n\tconst storage = options.persist === false ? undefined : new JsonGitHubCopilotAuthStorage(file);\n\treturn copilotOps(storage ?? transient, storage?.path ?? \"\");\n};\n\nexport const attempt = <A>(message: string, run: () => Promise<A>) =>\n\tEffect.tryPromise({ try: run, catch: (cause) => new OAuthError({ message, cause }) });\n\n/** The provider named by the two mutually exclusive flags. */\nexport const selectProvider = (flags: {\n\treadonly openaiCodex: boolean;\n\treadonly githubCopilot: boolean;\n}): Effect.Effect<Provider, InvalidInputError> => {\n\tconst checked = checkOAuthProvider(flags);\n\treturn checked.ok\n\t\t? Effect.succeed(checked.provider)\n\t\t: Effect.fail(new InvalidInputError({ message: checked.message }));\n};\n\n/** Reject the local-credential flags when the credentials live on a server. */\nexport const assertServerScope = (authFile: Option.Option<string>) =>\n\tEffect.gen(function* () {\n\t\tconst shared = yield* Cmd.spec;\n\t\tif (Option.isSome(authFile) || Option.isSome(shared.home)) {\n\t\t\treturn yield* new InvalidInputError({\n\t\t\t\tmessage: \"--auth-file and --home belong on codework serve when using --server\",\n\t\t\t});\n\t\t}\n\t});\n\n/** Credential operations against this machine's auth.json. */\nexport const localOps = (provider: Provider, authFile: Option.Option<string>) =>\n\tEffect.gen(function* () {\n\t\tconst shared = yield* Cmd.spec;\n\t\tconst path = yield* Path.Path;\n\t\tconst file = Option.isSome(authFile)\n\t\t\t? authFile.value\n\t\t\t: Option.isSome(shared.home)\n\t\t\t\t? path.join((yield* Global.resolve({ home: shared.home.value })).home, \"aikit\", \"auth.json\")\n\t\t\t\t: undefined;\n\t\treturn makeOps(provider, file === undefined ? {} : { path: file });\n\t});\n\n/** Run an effect against the RPC server at `url`, discharging the client. */\nexport const withServer = <A, E, R>(url: string, program: Effect.Effect<A, E, R>) =>\n\tprogram.pipe(Effect.provide(Client.layer(url)), Effect.scoped);\n\nexport { Client, oauthProviderLabel };\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { i as Cmd, t as handler } from "./runtime-CIBm_3RX.mjs";
1
+ import { i as Cmd, t as handler } from "./runtime-B43doHjV.mjs";
2
2
  import { d as writeOut, i as reportFailure } from "./error-CzUxh0Q9.mjs";
3
- import { i as ensure, n as options } from "./service-Eeg2xnZm.mjs";
3
+ import { i as ensure, n as options } from "./service-BnbxCw8H.mjs";
4
4
  import { Effect } from "effect";
5
5
  //#region src/cli/cmd/handlers/service/start.ts
6
6
  var start_default = handler(Cmd.commands.service.commands.start, Effect.fn("CLI.service.start")(function* ({ host, port }) {
@@ -17,4 +17,4 @@ var start_default = handler(Cmd.commands.service.commands.start, Effect.fn("CLI.
17
17
  //#endregion
18
18
  export { start_default as default };
19
19
 
20
- //# sourceMappingURL=start-nYFn6dNR.mjs.map
20
+ //# sourceMappingURL=start-DO3HjkNR.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"start-nYFn6dNR.mjs","names":["Runtime.handler","options","Service.options","Discovery.ensure"],"sources":["../../src/cli/cmd/handlers/service/start.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { Discovery } from \"../../../../server/discovery.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Service } from \"../../../service.ts\";\nimport { Cmd } from \"../../cmd.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.service.commands.start,\n\tEffect.fn(\"CLI.service.start\")(function* ({ host, port }) {\n\t\tconst options = yield* Service.options(yield* Cmd.spec, { host, port });\n\t\tconst server = yield* Discovery.ensure({ ...options, replace: true });\n\t\tyield* writeOut(`${server.url}\\n`);\n\t}, Effect.catch(reportFailure)),\n);\n"],"mappings":";;;;;AAQA,IAAA,gBAAeA,QACd,IAAI,SAAS,QAAQ,SAAS,OAC9B,OAAO,GAAG,mBAAmB,CAAC,CAAC,WAAW,EAAE,MAAM,QAAQ;CACzD,MAAMC,YAAU,OAAOC,QAAgB,OAAO,IAAI,MAAM;EAAE;EAAM;CAAK,CAAC;CACtE,MAAM,SAAS,OAAOC,OAAiB;EAAE,GAAGF;EAAS,SAAS;CAAK,CAAC;CACpE,OAAO,SAAS,GAAG,OAAO,IAAI,GAAG;AAClC,GAAG,OAAO,MAAM,aAAa,CAAC,CAC/B"}
1
+ {"version":3,"file":"start-DO3HjkNR.mjs","names":["Runtime.handler","options","Service.options","Discovery.ensure"],"sources":["../../src/cli/cmd/handlers/service/start.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { Discovery } from \"../../../../server/discovery.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Service } from \"../../../service.ts\";\nimport { Cmd } from \"../../cmd.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.service.commands.start,\n\tEffect.fn(\"CLI.service.start\")(function* ({ host, port }) {\n\t\tconst options = yield* Service.options(yield* Cmd.spec, { host, port });\n\t\tconst server = yield* Discovery.ensure({ ...options, replace: true });\n\t\tyield* writeOut(`${server.url}\\n`);\n\t}, Effect.catch(reportFailure)),\n);\n"],"mappings":";;;;;AAQA,IAAA,gBAAeA,QACd,IAAI,SAAS,QAAQ,SAAS,OAC9B,OAAO,GAAG,mBAAmB,CAAC,CAAC,WAAW,EAAE,MAAM,QAAQ;CACzD,MAAMC,YAAU,OAAOC,QAAgB,OAAO,IAAI,MAAM;EAAE;EAAM;CAAK,CAAC;CACtE,MAAM,SAAS,OAAOC,OAAiB;EAAE,GAAGF;EAAS,SAAS;CAAK,CAAC;CACpE,OAAO,SAAS,GAAG,OAAO,IAAI,GAAG;AAClC,GAAG,OAAO,MAAM,aAAa,CAAC,CAC/B"}
@@ -1,6 +1,6 @@
1
- import { i as Cmd, t as handler } from "./runtime-CIBm_3RX.mjs";
1
+ import { i as Cmd, t as handler } from "./runtime-B43doHjV.mjs";
2
2
  import { d as writeOut, i as reportFailure } from "./error-CzUxh0Q9.mjs";
3
- import { r as discover, t as home } from "./service-Eeg2xnZm.mjs";
3
+ import { r as discover, t as home } from "./service-BnbxCw8H.mjs";
4
4
  import { Effect } from "effect";
5
5
  //#region src/cli/cmd/handlers/service/status.ts
6
6
  var status_default = handler(Cmd.commands.service.commands.status, Effect.fn("CLI.service.status")(function* () {
@@ -11,4 +11,4 @@ var status_default = handler(Cmd.commands.service.commands.status, Effect.fn("CL
11
11
  //#endregion
12
12
  export { status_default as default };
13
13
 
14
- //# sourceMappingURL=status-DShPzrgm.mjs.map
14
+ //# sourceMappingURL=status-BQcs5jvy.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"status-DShPzrgm.mjs","names":["Runtime.handler","Service.home","Discovery.discover"],"sources":["../../src/cli/cmd/handlers/service/status.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { Discovery } from \"../../../../server/discovery.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Service } from \"../../../service.ts\";\nimport { Cmd } from \"../../cmd.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.service.commands.status,\n\tEffect.fn(\"CLI.service.status\")(function* () {\n\t\tconst paths = yield* Service.home(yield* Cmd.spec);\n\t\tconst server = yield* Discovery.discover(paths.home);\n\t\tyield* writeOut(`${server?.url ?? \"stopped\"}\\n`);\n\t}, Effect.catch(reportFailure)),\n);\n"],"mappings":";;;;;AAQA,IAAA,iBAAeA,QACd,IAAI,SAAS,QAAQ,SAAS,QAC9B,OAAO,GAAG,oBAAoB,CAAC,CAAC,aAAa;CAC5C,MAAM,QAAQ,OAAOC,KAAa,OAAO,IAAI,IAAI;CACjD,MAAM,SAAS,OAAOC,SAAmB,MAAM,IAAI;CACnD,OAAO,SAAS,GAAG,QAAQ,OAAO,UAAU,GAAG;AAChD,GAAG,OAAO,MAAM,aAAa,CAAC,CAC/B"}
1
+ {"version":3,"file":"status-BQcs5jvy.mjs","names":["Runtime.handler","Service.home","Discovery.discover"],"sources":["../../src/cli/cmd/handlers/service/status.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { Discovery } from \"../../../../server/discovery.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Service } from \"../../../service.ts\";\nimport { Cmd } from \"../../cmd.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.service.commands.status,\n\tEffect.fn(\"CLI.service.status\")(function* () {\n\t\tconst paths = yield* Service.home(yield* Cmd.spec);\n\t\tconst server = yield* Discovery.discover(paths.home);\n\t\tyield* writeOut(`${server?.url ?? \"stopped\"}\\n`);\n\t}, Effect.catch(reportFailure)),\n);\n"],"mappings":";;;;;AAQA,IAAA,iBAAeA,QACd,IAAI,SAAS,QAAQ,SAAS,QAC9B,OAAO,GAAG,oBAAoB,CAAC,CAAC,aAAa;CAC5C,MAAM,QAAQ,OAAOC,KAAa,OAAO,IAAI,IAAI;CACjD,MAAM,SAAS,OAAOC,SAAmB,MAAM,IAAI;CACnD,OAAO,SAAS,GAAG,QAAQ,OAAO,UAAU,GAAG;AAChD,GAAG,OAAO,MAAM,aAAa,CAAC,CAC/B"}
@@ -1,6 +1,6 @@
1
- import { i as Cmd, t as handler } from "./runtime-CIBm_3RX.mjs";
1
+ import { i as Cmd, t as handler } from "./runtime-B43doHjV.mjs";
2
2
  import { d as writeOut, i as reportFailure, n as OAuthError, p as make } from "./error-CzUxh0Q9.mjs";
3
- import { a as oauthProviderLabel, n as attempt, o as selectProvider, r as localOps, s as withServer, t as assertServerScope } from "./shared-DjyUhNsi.mjs";
3
+ import { a as oauthProviderLabel, n as attempt, o as selectProvider, r as localOps, s as withServer, t as assertServerScope } from "./shared-wNZoC017.mjs";
4
4
  import { Effect, Option } from "effect";
5
5
  import { formatOAuthSummary, oauthNotice } from "@codeworksh/aikit/oauth/summary";
6
6
  //#region src/cli/cmd/handlers/auth/status.ts
@@ -28,4 +28,4 @@ var status_default = handler(Cmd.commands.auth.commands.status, Effect.fn("CLI.a
28
28
  //#endregion
29
29
  export { status_default as default };
30
30
 
31
- //# sourceMappingURL=status-BTCqpq7x.mjs.map
31
+ //# sourceMappingURL=status-CQHqU7_7.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"status-BTCqpq7x.mjs","names":["Runtime.handler","Client.make"],"sources":["../../src/cli/cmd/handlers/auth/status.ts"],"sourcesContent":["import { formatOAuthSummary, oauthNotice } from \"@codeworksh/aikit/oauth/summary\";\nimport { Effect, Option } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { OAuthError, reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport {\n\tassertServerScope,\n\tattempt,\n\tClient,\n\tlocalOps,\n\toauthProviderLabel,\n\tselectProvider,\n\twithServer,\n} from \"./shared.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.auth.commands.status,\n\tEffect.fn(\"CLI.auth.status\")(function* ({ server, openaiCodex, githubCopilot, authFile, json }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst provider = yield* selectProvider({ openaiCodex, githubCopilot });\n\t\t\tconst name = oauthProviderLabel(provider);\n\n\t\t\tif (Option.isSome(server)) {\n\t\t\t\tyield* assertServerScope(authFile);\n\t\t\t\treturn yield* withServer(\n\t\t\t\t\tserver.value,\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst rpc = yield* Client.make;\n\t\t\t\t\t\tconst info = yield* rpc[\"auth.status\"]({ provider });\n\t\t\t\t\t\tif (info === null) {\n\t\t\t\t\t\t\treturn yield* new OAuthError({ message: oauthNotice(\"missing\", provider, \"the server\") });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyield* writeOut(formatOAuthSummary(info, { json }));\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst ops = yield* localOps(provider, authFile);\n\t\t\tconst summary = yield* attempt(`failed to read ${name} credentials`, () => ops.stored());\n\t\t\tif (summary === undefined) {\n\t\t\t\treturn yield* new OAuthError({ message: oauthNotice(\"missing\", provider, ops.path) });\n\t\t\t}\n\t\t\tyield* writeOut(formatOAuthSummary(summary, { json }));\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":";;;;;;AAgBA,IAAA,iBAAeA,QACd,IAAI,SAAS,KAAK,SAAS,QAC3B,OAAO,GAAG,iBAAiB,CAAC,CAAC,WAAW,EAAE,QAAQ,aAAa,eAAe,UAAU,QAAQ;CA4B/F,OAAO,OA3BS,OAAO,IAAI,aAAa;EACvC,MAAM,WAAW,OAAO,eAAe;GAAE;GAAa;EAAc,CAAC;EACrE,MAAM,OAAO,mBAAmB,QAAQ;EAExC,IAAI,OAAO,OAAO,MAAM,GAAG;GAC1B,OAAO,kBAAkB,QAAQ;GACjC,OAAO,OAAO,WACb,OAAO,OACP,OAAO,IAAI,aAAa;IAEvB,MAAM,OAAO,QAAO,OADDC,KAAAA,CACK,cAAc,CAAC,EAAE,SAAS,CAAC;IACnD,IAAI,SAAS,MACZ,OAAO,OAAO,IAAI,WAAW,EAAE,SAAS,YAAY,WAAW,UAAU,YAAY,EAAE,CAAC;IAEzF,OAAO,SAAS,mBAAmB,MAAM,EAAE,KAAK,CAAC,CAAC;GACnD,CAAC,CACF;EACD;EAEA,MAAM,MAAM,OAAO,SAAS,UAAU,QAAQ;EAC9C,MAAM,UAAU,OAAO,QAAQ,kBAAkB,KAAK,qBAAqB,IAAI,OAAO,CAAC;EACvF,IAAI,YAAY,KAAA,GACf,OAAO,OAAO,IAAI,WAAW,EAAE,SAAS,YAAY,WAAW,UAAU,IAAI,IAAI,EAAE,CAAC;EAErF,OAAO,SAAS,mBAAmB,SAAS,EAAE,KAAK,CAAC,CAAC;CACtD,CAEoB,CAAC,CAAC,KAAK,OAAO,MAAM,aAAa,CAAC;AACvD,CAAC,CACF"}
1
+ {"version":3,"file":"status-CQHqU7_7.mjs","names":["Runtime.handler","Client.make"],"sources":["../../src/cli/cmd/handlers/auth/status.ts"],"sourcesContent":["import { formatOAuthSummary, oauthNotice } from \"@codeworksh/aikit/oauth/summary\";\nimport { Effect, Option } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { OAuthError, reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport {\n\tassertServerScope,\n\tattempt,\n\tClient,\n\tlocalOps,\n\toauthProviderLabel,\n\tselectProvider,\n\twithServer,\n} from \"./shared.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.auth.commands.status,\n\tEffect.fn(\"CLI.auth.status\")(function* ({ server, openaiCodex, githubCopilot, authFile, json }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst provider = yield* selectProvider({ openaiCodex, githubCopilot });\n\t\t\tconst name = oauthProviderLabel(provider);\n\n\t\t\tif (Option.isSome(server)) {\n\t\t\t\tyield* assertServerScope(authFile);\n\t\t\t\treturn yield* withServer(\n\t\t\t\t\tserver.value,\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst rpc = yield* Client.make;\n\t\t\t\t\t\tconst info = yield* rpc[\"auth.status\"]({ provider });\n\t\t\t\t\t\tif (info === null) {\n\t\t\t\t\t\t\treturn yield* new OAuthError({ message: oauthNotice(\"missing\", provider, \"the server\") });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tyield* writeOut(formatOAuthSummary(info, { json }));\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst ops = yield* localOps(provider, authFile);\n\t\t\tconst summary = yield* attempt(`failed to read ${name} credentials`, () => ops.stored());\n\t\t\tif (summary === undefined) {\n\t\t\t\treturn yield* new OAuthError({ message: oauthNotice(\"missing\", provider, ops.path) });\n\t\t\t}\n\t\t\tyield* writeOut(formatOAuthSummary(summary, { json }));\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":";;;;;;AAgBA,IAAA,iBAAeA,QACd,IAAI,SAAS,KAAK,SAAS,QAC3B,OAAO,GAAG,iBAAiB,CAAC,CAAC,WAAW,EAAE,QAAQ,aAAa,eAAe,UAAU,QAAQ;CA4B/F,OAAO,OA3BS,OAAO,IAAI,aAAa;EACvC,MAAM,WAAW,OAAO,eAAe;GAAE;GAAa;EAAc,CAAC;EACrE,MAAM,OAAO,mBAAmB,QAAQ;EAExC,IAAI,OAAO,OAAO,MAAM,GAAG;GAC1B,OAAO,kBAAkB,QAAQ;GACjC,OAAO,OAAO,WACb,OAAO,OACP,OAAO,IAAI,aAAa;IAEvB,MAAM,OAAO,QAAO,OADDC,KAAAA,CACK,cAAc,CAAC,EAAE,SAAS,CAAC;IACnD,IAAI,SAAS,MACZ,OAAO,OAAO,IAAI,WAAW,EAAE,SAAS,YAAY,WAAW,UAAU,YAAY,EAAE,CAAC;IAEzF,OAAO,SAAS,mBAAmB,MAAM,EAAE,KAAK,CAAC,CAAC;GACnD,CAAC,CACF;EACD;EAEA,MAAM,MAAM,OAAO,SAAS,UAAU,QAAQ;EAC9C,MAAM,UAAU,OAAO,QAAQ,kBAAkB,KAAK,qBAAqB,IAAI,OAAO,CAAC;EACvF,IAAI,YAAY,KAAA,GACf,OAAO,OAAO,IAAI,WAAW,EAAE,SAAS,YAAY,WAAW,UAAU,IAAI,IAAI,EAAE,CAAC;EAErF,OAAO,SAAS,mBAAmB,SAAS,EAAE,KAAK,CAAC,CAAC;CACtD,CAEoB,CAAC,CAAC,KAAK,OAAO,MAAM,aAAa,CAAC;AACvD,CAAC,CACF"}
@@ -1,6 +1,6 @@
1
- import { i as Cmd, t as handler } from "./runtime-CIBm_3RX.mjs";
1
+ import { i as Cmd, t as handler } from "./runtime-B43doHjV.mjs";
2
2
  import { i as reportFailure } from "./error-CzUxh0Q9.mjs";
3
- import { o as stop, t as home } from "./service-Eeg2xnZm.mjs";
3
+ import { o as stop, t as home } from "./service-BnbxCw8H.mjs";
4
4
  import { Effect } from "effect";
5
5
  //#region src/cli/cmd/handlers/service/stop.ts
6
6
  var stop_default = handler(Cmd.commands.service.commands.stop, Effect.fn("CLI.service.stop")(function* () {
@@ -10,4 +10,4 @@ var stop_default = handler(Cmd.commands.service.commands.stop, Effect.fn("CLI.se
10
10
  //#endregion
11
11
  export { stop_default as default };
12
12
 
13
- //# sourceMappingURL=stop-Bx6q-OsW.mjs.map
13
+ //# sourceMappingURL=stop-CbszhOq5.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"stop-Bx6q-OsW.mjs","names":["Runtime.handler","Service.home","Discovery.stop"],"sources":["../../src/cli/cmd/handlers/service/stop.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { Discovery } from \"../../../../server/discovery.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { Service } from \"../../../service.ts\";\nimport { Cmd } from \"../../cmd.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.service.commands.stop,\n\tEffect.fn(\"CLI.service.stop\")(function* () {\n\t\tconst paths = yield* Service.home(yield* Cmd.spec);\n\t\tyield* Discovery.stop(paths.home);\n\t}, Effect.catch(reportFailure)),\n);\n"],"mappings":";;;;;AAOA,IAAA,eAAeA,QACd,IAAI,SAAS,QAAQ,SAAS,MAC9B,OAAO,GAAG,kBAAkB,CAAC,CAAC,aAAa;CAC1C,MAAM,QAAQ,OAAOC,KAAa,OAAO,IAAI,IAAI;CACjD,OAAOC,KAAe,MAAM,IAAI;AACjC,GAAG,OAAO,MAAM,aAAa,CAAC,CAC/B"}
1
+ {"version":3,"file":"stop-CbszhOq5.mjs","names":["Runtime.handler","Service.home","Discovery.stop"],"sources":["../../src/cli/cmd/handlers/service/stop.ts"],"sourcesContent":["import { Effect } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { Discovery } from \"../../../../server/discovery.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { Service } from \"../../../service.ts\";\nimport { Cmd } from \"../../cmd.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.service.commands.stop,\n\tEffect.fn(\"CLI.service.stop\")(function* () {\n\t\tconst paths = yield* Service.home(yield* Cmd.spec);\n\t\tyield* Discovery.stop(paths.home);\n\t}, Effect.catch(reportFailure)),\n);\n"],"mappings":";;;;;AAOA,IAAA,eAAeA,QACd,IAAI,SAAS,QAAQ,SAAS,MAC9B,OAAO,GAAG,kBAAkB,CAAC,CAAC,aAAa;CAC1C,MAAM,QAAQ,OAAOC,KAAa,OAAO,IAAI,IAAI;CACjD,OAAOC,KAAe,MAAM,IAAI;AACjC,GAAG,OAAO,MAAM,aAAa,CAAC,CAC/B"}
@@ -1,7 +1,7 @@
1
- import { i as Cmd, t as handler } from "./runtime-CIBm_3RX.mjs";
1
+ import { i as Cmd, t as handler } from "./runtime-B43doHjV.mjs";
2
2
  import { r as renderError, t as InvalidInputError, u as writeError } from "./error-CzUxh0Q9.mjs";
3
- import { n as current } from "./identity-KihnHS0K.mjs";
4
- import { a as keepAlive, i as ensure, n as options, s as probe } from "./service-Eeg2xnZm.mjs";
3
+ import { n as current } from "./identity-BfMXCqOi.mjs";
4
+ import { a as keepAlive, i as ensure, n as options, s as probe } from "./service-BnbxCw8H.mjs";
5
5
  import { Effect, Option } from "effect";
6
6
  import { ChildProcess, ChildProcessSpawner } from "effect/process";
7
7
  //#region src/cli/cmd/handlers/tui.ts
@@ -43,7 +43,7 @@ const run = (binary, args, env) => Effect.gen(function* () {
43
43
  stderr: "inherit"
44
44
  }))).exitCode.pipe(Effect.orElseSucceed(() => 1));
45
45
  }).pipe(Effect.scoped);
46
- var tui_default = handler(Cmd.commands.tui, Effect.fn("CLI.tui")(function* ({ server, host, port, args }) {
46
+ var tui_default = handler(Cmd.commands.tui, Effect.fn("CLI.tui", { level: "Info" })(function* ({ server, host, port, args }) {
47
47
  const shared = yield* Cmd.spec;
48
48
  const code = yield* Effect.gen(function* () {
49
49
  if (Option.isSome(server) && [
@@ -73,4 +73,4 @@ var tui_default = handler(Cmd.commands.tui, Effect.fn("CLI.tui")(function* ({ se
73
73
  //#endregion
74
74
  export { tui_default as default };
75
75
 
76
- //# sourceMappingURL=tui-ChaAFDdS.mjs.map
76
+ //# sourceMappingURL=tui-CxBfJvv5.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-CxBfJvv5.mjs","names":["Health.probe","Discovery.ensure","Discovery.keepAlive","Runtime.handler","options","Service.options"],"sources":["../../src/cli/cmd/handlers/tui.ts"],"sourcesContent":["import { Effect, Option } from \"effect\";\nimport { ChildProcess, ChildProcessSpawner } from \"effect/process\";\nimport { Runtime } from \"../../../framework/runtime.ts\";\nimport { Discovery } from \"../../../server/discovery.ts\";\nimport { Health } from \"../../../server/health.ts\";\nimport { Identity } from \"../../../server/identity.ts\";\nimport { InvalidInputError, renderError } from \"../../error.ts\";\nimport { writeError } from \"../../output.ts\";\nimport { Service } from \"../../service.ts\";\nimport { Cmd } from \"../cmd.ts\";\n\n/**\n * Adopt a server the user started, only if it answers `server.info`: the UI must\n * never launch against an endpoint that is not a CodeWork server. A different\n * build is allowed, with a warning, because the user chose it.\n */\nconst attach = (url: string) =>\n\tEffect.gen(function* () {\n\t\tconst info = yield* Health.probe(url);\n\t\tif (info === undefined) return yield* new InvalidInputError({ message: `no CodeWork server answered at ${url}` });\n\t\tif (info.version !== Identity.current.version) {\n\t\t\tyield* Effect.sync(() =>\n\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t`warning: server at ${url} runs ${info.version}; this client is ${Identity.current.version}\\n`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn url;\n\t});\n\n/** Start or reuse the local server, and keep it up while the TUI runs. */\nconst managed = (options: Discovery.Options) =>\n\tEffect.gen(function* () {\n\t\tconst resolved = yield* Discovery.ensure({\n\t\t\t...options,\n\t\t\t// An upgraded CLI must not drive a server from an older build.\n\t\t\treplace: true,\n\t\t\tonStart: (reason) =>\n\t\t\t\tvoid process.stderr.write(\n\t\t\t\t\treason === \"version-mismatch\"\n\t\t\t\t\t\t? \"Restarting CodeWork server (version mismatch)...\\n\"\n\t\t\t\t\t\t: `Starting CodeWork server on ${options.host}:${options.port}...\\n`,\n\t\t\t\t),\n\t\t});\n\t\t// The TUI only reconnects; restoring a server that dies under it is ours to do.\n\t\tyield* Discovery.keepAlive(resolved, options).pipe(Effect.forkScoped);\n\t\treturn resolved.url;\n\t});\n\n/**\n * Run the TUI in the foreground, on this terminal, for as long as this command\n * runs. It stays in this process group (`detached: false`) so it keeps the\n * terminal; stdio is inherited because it draws and reads raw keys itself. The\n * scope is what ties their lifetimes: when this command is interrupted (SIGINT,\n * SIGTERM), closing it terminates the TUI rather than leaving it on the screen.\n */\nconst run = (binary: string, args: ReadonlyArray<string>, env: Record<string, string>) =>\n\tEffect.gen(function* () {\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner;\n\t\tconst tui = yield* spawner.spawn(\n\t\t\tChildProcess.make(binary, [...args], {\n\t\t\t\tenv,\n\t\t\t\textendEnv: true,\n\t\t\t\tdetached: false,\n\t\t\t\tstdin: \"inherit\",\n\t\t\t\tstdout: \"inherit\",\n\t\t\t\tstderr: \"inherit\",\n\t\t\t}),\n\t\t);\n\t\t// A TUI killed by a signal has no exit code; it still must not read as success.\n\t\treturn yield* tui.exitCode.pipe(Effect.orElseSucceed(() => 1));\n\t}).pipe(Effect.scoped);\n\nexport default Runtime.handler(\n\tCmd.commands.tui,\n\tEffect.fn(\"CLI.tui\", { level: \"Info\" })(function* ({ server, host, port, args }) {\n\t\tconst shared = yield* Cmd.spec;\n\n\t\tconst program = Effect.gen(function* () {\n\t\t\tif (Option.isSome(server) && [shared.home, shared.database, shared.userConfigDir].some(Option.isSome)) {\n\t\t\t\treturn yield* new InvalidInputError({\n\t\t\t\t\tmessage: \"--home, --database, and --user-config-dir belong on codework serve when using --server\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst options = yield* Service.options(shared, { host, port });\n\t\t\tconst url = yield* Option.isSome(server) ? attach(server.value) : managed(options);\n\n\t\t\t// Imported lazily: binary resolution must stay off the path of every other command.\n\t\t\tconst launcher = yield* Effect.promise(() => import(\"@codeworksh/tui\"));\n\t\t\tconst binary = yield* Effect.try({\n\t\t\t\ttry: () => launcher.resolveBinary(),\n\t\t\t\tcatch: (error) => new InvalidInputError({ message: (error as Error).message }),\n\t\t\t});\n\t\t\treturn yield* run(binary, args, {\n\t\t\t\t[launcher.ENV_SERVER]: url,\n\t\t\t\t// The TUI reads its own config and credentials, so it must resolve the same home\n\t\t\t\t// the server uses; otherwise the UI would show a different installation.\n\t\t\t\tCODEWORK_HOME_DIR: options.home,\n\t\t\t});\n\t\t});\n\n\t\tconst code = yield* program.pipe(\n\t\t\tEffect.scoped,\n\t\t\tEffect.catch((error) => writeError(renderError(error)).pipe(Effect.as(1))),\n\t\t);\n\t\tyield* Effect.sync(() => {\n\t\t\tprocess.exitCode = code;\n\t\t});\n\t}),\n);\n"],"mappings":";;;;;;;;;;;;AAgBA,MAAM,UAAU,QACf,OAAO,IAAI,aAAa;CACvB,MAAM,OAAO,OAAOA,MAAa,GAAG;CACpC,IAAI,SAAS,KAAA,GAAW,OAAO,OAAO,IAAI,kBAAkB,EAAE,SAAS,kCAAkC,MAAM,CAAC;CAChH,IAAI,KAAK,YAAA,QAA6B,SACrC,OAAO,OAAO,WACb,QAAQ,OAAO,MACd,sBAAsB,IAAI,QAAQ,KAAK,QAAQ,mBAAA,QAAoC,QAAQ,GAC5F,CACD;CAED,OAAO;AACR,CAAC;;AAGF,MAAM,WAAW,YAChB,OAAO,IAAI,aAAa;CACvB,MAAM,WAAW,OAAOC,OAAiB;EACxC,GAAG;EAEH,SAAS;EACT,UAAU,WACT,KAAK,QAAQ,OAAO,MACnB,WAAW,qBACR,uDACA,+BAA+B,QAAQ,KAAK,GAAG,QAAQ,KAAK,MAChE;CACF,CAAC;CAED,OAAOC,UAAoB,UAAU,OAAO,CAAC,CAAC,KAAK,OAAO,UAAU;CACpE,OAAO,SAAS;AACjB,CAAC;;;;;;;;AASF,MAAM,OAAO,QAAgB,MAA6B,QACzD,OAAO,IAAI,aAAa;CAavB,OAAO,QAAO,QAXK,OADI,oBAAoB,oBAAA,CAChB,MAC1B,aAAa,KAAK,QAAQ,CAAC,GAAG,IAAI,GAAG;EACpC;EACA,WAAW;EACX,UAAU;EACV,OAAO;EACP,QAAQ;EACR,QAAQ;CACT,CAAC,CACF,EAAA,CAEkB,SAAS,KAAK,OAAO,oBAAoB,CAAC,CAAC;AAC9D,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM;AAEtB,IAAA,cAAeC,QACd,IAAI,SAAS,KACb,OAAO,GAAG,WAAW,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,QAAQ,MAAM,MAAM,QAAQ;CAChF,MAAM,SAAS,OAAO,IAAI;CA0B1B,MAAM,OAAO,OAxBG,OAAO,IAAI,aAAa;EACvC,IAAI,OAAO,OAAO,MAAM,KAAK;GAAC,OAAO;GAAM,OAAO;GAAU,OAAO;EAAa,CAAC,CAAC,KAAK,OAAO,MAAM,GACnG,OAAO,OAAO,IAAI,kBAAkB,EACnC,SAAS,yFACV,CAAC;EAGF,MAAMC,YAAU,OAAOC,QAAgB,QAAQ;GAAE;GAAM;EAAK,CAAC;EAC7D,MAAM,MAAM,OAAO,OAAO,OAAO,MAAM,IAAI,OAAO,OAAO,KAAK,IAAI,QAAQD,SAAO;EAGjF,MAAM,WAAW,OAAO,OAAO,cAAc,OAAO,kBAAkB;EACtE,MAAM,SAAS,OAAO,OAAO,IAAI;GAChC,WAAW,SAAS,cAAc;GAClC,QAAQ,UAAU,IAAI,kBAAkB,EAAE,SAAU,MAAgB,QAAQ,CAAC;EAC9E,CAAC;EACD,OAAO,OAAO,IAAI,QAAQ,MAAM;IAC9B,SAAS,aAAa;GAGvB,mBAAmBA,UAAQ;EAC5B,CAAC;CACF,CAE0B,CAAC,CAAC,KAC3B,OAAO,QACP,OAAO,OAAO,UAAU,WAAW,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,CAC1E;CACA,OAAO,OAAO,WAAW;EACxB,QAAQ,WAAW;CACpB,CAAC;AACF,CAAC,CACF"}
@@ -1,4 +1,4 @@
1
- import { i as Cmd, t as handler } from "./runtime-CIBm_3RX.mjs";
1
+ import { i as Cmd, t as handler } from "./runtime-B43doHjV.mjs";
2
2
  import { d as writeOut, i as reportFailure } from "./error-CzUxh0Q9.mjs";
3
3
  import { a as targeted, i as read, n as local, r as probe, t as fetchable } from "./entries-8LFGwy4n.mjs";
4
4
  import { Effect, Option } from "effect";
@@ -48,4 +48,4 @@ var update_default = handler(Cmd.commands.plugin.commands.update, Effect.fn("CLI
48
48
  //#endregion
49
49
  export { update_default as default };
50
50
 
51
- //# sourceMappingURL=update-6Fn2_4fJ.mjs.map
51
+ //# sourceMappingURL=update-CfrkcWoW.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"update-6Fn2_4fJ.mjs","names":["Runtime.handler"],"sources":["../../src/cli/cmd/handlers/plugin/update.ts"],"sourcesContent":["import { Plugin } from \"@codeworksh/harness/effect\";\nimport { Effect, Option } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport { fetchable, local, probe, read, targeted } from \"./entries.ts\";\n\n/**\n * Take whatever `check` found.\n *\n * Only a plugin that is **already installed** is refreshed: \"not installed\" is not \"outdated\", and\n * `plugin install` is the verb for that. Each refresh publishes a new generation, which a running\n * session picks up at its next exchange -- so this command never has to reach into a server.\n */\nexport default Runtime.handler(\n\tCmd.commands.plugin.commands.update,\n\tEffect.fn(\"CLI.plugin.update\")(function* ({ spec }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst shared = yield* Cmd.spec;\n\t\t\tconst { entries, cache, hostDir } = yield* read(shared);\n\t\t\tconst selected = yield* targeted(entries, spec, hostDir);\n\t\t\tif (selected.length === 0 && Option.isSome(spec)) return;\n\n\t\t\tlet updated = 0;\n\t\t\tlet failed = 0;\n\t\t\tfor (const entry of selected) {\n\t\t\t\tconst target = fetchable(entry.target);\n\t\t\t\t// A local plugin has no revision to compare and is never copied into the store.\n\t\t\t\tif (target === undefined) {\n\t\t\t\t\tyield* local(entry, spec);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst result = yield* Plugin.update(target, cache, {\n\t\t\t\t\tprobe: probe(cache, entry.from),\n\t\t\t\t\tfrom: entry.from,\n\t\t\t\t\t// Validated while staged, so a refresh that fetches something broken leaves\n\t\t\t\t\t// the generation already in use as the answer. Preserve the loader's reason:\n\t\t\t\t\t// an import failure or invalid definition is not a missing entrypoint.\n\t\t\t\t\tvalidate: (fetched) => Plugin.definition(fetched.entrypoint, entry.reference).pipe(Effect.asVoid),\n\t\t\t\t}).pipe(Effect.result);\n\n\t\t\t\tif (result._tag === \"Failure\") {\n\t\t\t\t\tfailed += 1;\n\t\t\t\t\tyield* writeOut(`${entry.reference} error[${result.failure.reason}]: ${result.failure.message}\\n`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (result.success._tag === \"updated\") {\n\t\t\t\t\tupdated += 1;\n\t\t\t\t\tyield* writeOut(`Updated ${entry.reference} to ${result.success.entry.revision ?? \"a new revision\"}\\n`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A spec that named only local plugins compared nothing, so there is nothing to sum up.\n\t\t\tif (Option.isSome(spec) && selected.every((entry) => fetchable(entry.target) === undefined)) return;\n\t\t\tyield* writeOut(updated === 0 ? \"Nothing to update.\\n\" : `${updated} updated.\\n`);\n\t\t\tif (failed > 0) process.exitCode = 1;\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":";;;;;;;;;;;;;AAeA,IAAA,iBAAeA,QACd,IAAI,SAAS,OAAO,SAAS,QAC7B,OAAO,GAAG,mBAAmB,CAAC,CAAC,WAAW,EAAE,QAAQ;CA2CnD,OAAO,OA1CS,OAAO,IAAI,aAAa;EACvC,MAAM,SAAS,OAAO,IAAI;EAC1B,MAAM,EAAE,SAAS,OAAO,YAAY,OAAO,KAAK,MAAM;EACtD,MAAM,WAAW,OAAO,SAAS,SAAS,MAAM,OAAO;EACvD,IAAI,SAAS,WAAW,KAAK,OAAO,OAAO,IAAI,GAAG;EAElD,IAAI,UAAU;EACd,IAAI,SAAS;EACb,KAAK,MAAM,SAAS,UAAU;GAC7B,MAAM,SAAS,UAAU,MAAM,MAAM;GAErC,IAAI,WAAW,KAAA,GAAW;IACzB,OAAO,MAAM,OAAO,IAAI;IACxB;GACD;GAEA,MAAM,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO;IAClD,OAAO,MAAM,OAAO,MAAM,IAAI;IAC9B,MAAM,MAAM;IAIZ,WAAW,YAAY,OAAO,WAAW,QAAQ,YAAY,MAAM,SAAS,CAAC,CAAC,KAAK,OAAO,MAAM;GACjG,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM;GAErB,IAAI,OAAO,SAAS,WAAW;IAC9B,UAAU;IACV,OAAO,SAAS,GAAG,MAAM,UAAU,UAAU,OAAO,QAAQ,OAAO,KAAK,OAAO,QAAQ,QAAQ,GAAG;IAClG;GACD;GACA,IAAI,OAAO,QAAQ,SAAS,WAAW;IACtC,WAAW;IACX,OAAO,SAAS,WAAW,MAAM,UAAU,MAAM,OAAO,QAAQ,MAAM,YAAY,iBAAiB,GAAG;GACvG;EACD;EAGA,IAAI,OAAO,OAAO,IAAI,KAAK,SAAS,OAAO,UAAU,UAAU,MAAM,MAAM,MAAM,KAAA,CAAS,GAAG;EAC7F,OAAO,SAAS,YAAY,IAAI,yBAAyB,GAAG,QAAQ,YAAY;EAChF,IAAI,SAAS,GAAG,QAAQ,WAAW;CACpC,CAEoB,CAAC,CAAC,KAAK,OAAO,MAAM,aAAa,CAAC;AACvD,CAAC,CACF"}
1
+ {"version":3,"file":"update-CfrkcWoW.mjs","names":["Runtime.handler"],"sources":["../../src/cli/cmd/handlers/plugin/update.ts"],"sourcesContent":["import { Plugin } from \"@codeworksh/harness/effect\";\nimport { Effect, Option } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport { fetchable, local, probe, read, targeted } from \"./entries.ts\";\n\n/**\n * Take whatever `check` found.\n *\n * Only a plugin that is **already installed** is refreshed: \"not installed\" is not \"outdated\", and\n * `plugin install` is the verb for that. Each refresh publishes a new generation, which a running\n * session picks up at its next exchange -- so this command never has to reach into a server.\n */\nexport default Runtime.handler(\n\tCmd.commands.plugin.commands.update,\n\tEffect.fn(\"CLI.plugin.update\")(function* ({ spec }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst shared = yield* Cmd.spec;\n\t\t\tconst { entries, cache, hostDir } = yield* read(shared);\n\t\t\tconst selected = yield* targeted(entries, spec, hostDir);\n\t\t\tif (selected.length === 0 && Option.isSome(spec)) return;\n\n\t\t\tlet updated = 0;\n\t\t\tlet failed = 0;\n\t\t\tfor (const entry of selected) {\n\t\t\t\tconst target = fetchable(entry.target);\n\t\t\t\t// A local plugin has no revision to compare and is never copied into the store.\n\t\t\t\tif (target === undefined) {\n\t\t\t\t\tyield* local(entry, spec);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst result = yield* Plugin.update(target, cache, {\n\t\t\t\t\tprobe: probe(cache, entry.from),\n\t\t\t\t\tfrom: entry.from,\n\t\t\t\t\t// Validated while staged, so a refresh that fetches something broken leaves\n\t\t\t\t\t// the generation already in use as the answer. Preserve the loader's reason:\n\t\t\t\t\t// an import failure or invalid definition is not a missing entrypoint.\n\t\t\t\t\tvalidate: (fetched) => Plugin.definition(fetched.entrypoint, entry.reference).pipe(Effect.asVoid),\n\t\t\t\t}).pipe(Effect.result);\n\n\t\t\t\tif (result._tag === \"Failure\") {\n\t\t\t\t\tfailed += 1;\n\t\t\t\t\tyield* writeOut(`${entry.reference} error[${result.failure.reason}]: ${result.failure.message}\\n`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (result.success._tag === \"updated\") {\n\t\t\t\t\tupdated += 1;\n\t\t\t\t\tyield* writeOut(`Updated ${entry.reference} to ${result.success.entry.revision ?? \"a new revision\"}\\n`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// A spec that named only local plugins compared nothing, so there is nothing to sum up.\n\t\t\tif (Option.isSome(spec) && selected.every((entry) => fetchable(entry.target) === undefined)) return;\n\t\t\tyield* writeOut(updated === 0 ? \"Nothing to update.\\n\" : `${updated} updated.\\n`);\n\t\t\tif (failed > 0) process.exitCode = 1;\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":";;;;;;;;;;;;;AAeA,IAAA,iBAAeA,QACd,IAAI,SAAS,OAAO,SAAS,QAC7B,OAAO,GAAG,mBAAmB,CAAC,CAAC,WAAW,EAAE,QAAQ;CA2CnD,OAAO,OA1CS,OAAO,IAAI,aAAa;EACvC,MAAM,SAAS,OAAO,IAAI;EAC1B,MAAM,EAAE,SAAS,OAAO,YAAY,OAAO,KAAK,MAAM;EACtD,MAAM,WAAW,OAAO,SAAS,SAAS,MAAM,OAAO;EACvD,IAAI,SAAS,WAAW,KAAK,OAAO,OAAO,IAAI,GAAG;EAElD,IAAI,UAAU;EACd,IAAI,SAAS;EACb,KAAK,MAAM,SAAS,UAAU;GAC7B,MAAM,SAAS,UAAU,MAAM,MAAM;GAErC,IAAI,WAAW,KAAA,GAAW;IACzB,OAAO,MAAM,OAAO,IAAI;IACxB;GACD;GAEA,MAAM,SAAS,OAAO,OAAO,OAAO,QAAQ,OAAO;IAClD,OAAO,MAAM,OAAO,MAAM,IAAI;IAC9B,MAAM,MAAM;IAIZ,WAAW,YAAY,OAAO,WAAW,QAAQ,YAAY,MAAM,SAAS,CAAC,CAAC,KAAK,OAAO,MAAM;GACjG,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM;GAErB,IAAI,OAAO,SAAS,WAAW;IAC9B,UAAU;IACV,OAAO,SAAS,GAAG,MAAM,UAAU,UAAU,OAAO,QAAQ,OAAO,KAAK,OAAO,QAAQ,QAAQ,GAAG;IAClG;GACD;GACA,IAAI,OAAO,QAAQ,SAAS,WAAW;IACtC,WAAW;IACX,OAAO,SAAS,WAAW,MAAM,UAAU,MAAM,OAAO,QAAQ,MAAM,YAAY,iBAAiB,GAAG;GACvG;EACD;EAGA,IAAI,OAAO,OAAO,IAAI,KAAK,SAAS,OAAO,UAAU,UAAU,MAAM,MAAM,MAAM,KAAA,CAAS,GAAG;EAC7F,OAAO,SAAS,YAAY,IAAI,yBAAyB,GAAG,QAAQ,YAAY;EAChF,IAAI,SAAS,GAAG,QAAQ,WAAW;CACpC,CAEoB,CAAC,CAAC,KAAK,OAAO,MAAM,aAAa,CAAC;AACvD,CAAC,CACF"}
@@ -1,6 +0,0 @@
1
- //#region package.json
2
- var version = "0.2.0-canary.17.1.gd1cf9b0f";
3
- //#endregion
4
- export { version as t };
5
-
6
- //# sourceMappingURL=package-8_CE-vpn.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"package-8_CE-vpn.mjs","names":[],"sources":["../../package.json"],"sourcesContent":[""],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"run-DKKbRyIo.mjs","names":["Runtime.handler","Client.make","Client.run","Client.layer"],"sources":["../../src/cli/cmd/handlers/run.ts"],"sourcesContent":["import { EventList, type EventSchema, Harness, Sandbox, Session } from \"@codeworksh/harness/effect\";\nimport { Effect, Exit, Fiber, Logger, Option, Queue, Ref, Schema, Stream } from \"effect\";\nimport { Runtime } from \"../../../framework/runtime.ts\";\nimport { Client } from \"../../../server/client.ts\";\nimport { InvalidInputError, renderError } from \"../../error.ts\";\nimport { harnessOptions } from \"../../harness.ts\";\nimport {\n\taddUsage,\n\temptyUsage,\n\theader,\n\tterminalColumns,\n\tusage,\n\ttype UsageSummary,\n\twriteError,\n\twriteOut,\n} from \"../../output.ts\";\nimport { Cmd } from \"../cmd.ts\";\n\ninterface RenderState {\n\treadonly usage: UsageSummary;\n\treadonly textSeen: boolean;\n\treadonly textEndsWithNewline: boolean;\n}\n\nconst initialRenderState: RenderState = {\n\tusage: emptyUsage,\n\ttextSeen: false,\n\ttextEndsWithNewline: false,\n};\n\nconst isTextDelta = Schema.is(EventList.LLMTextDelta);\nconst isLLMEnded = Schema.is(EventList.LLMEnded);\nconst isTurnEnded = Schema.is(EventList.TurnEnded);\n\nconst render = (state: Ref.Ref<RenderState>, ended?: Queue.Queue<string>) =>\n\tEffect.fn(\"CLI.render\")(function* (event: EventSchema.Payload) {\n\t\tif (isTextDelta(event)) {\n\t\t\tyield* writeOut(event.data.delta);\n\t\t\tif (event.data.delta.length > 0) {\n\t\t\t\tyield* Ref.update(state, (current) => ({\n\t\t\t\t\t...current,\n\t\t\t\t\ttextSeen: true,\n\t\t\t\t\ttextEndsWithNewline: event.data.delta.endsWith(\"\\n\"),\n\t\t\t\t}));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (isLLMEnded(event)) {\n\t\t\tyield* Ref.update(state, (current) => ({ ...current, usage: addUsage(current.usage, event.data.message) }));\n\t\t\treturn;\n\t\t}\n\t\tif (ended !== undefined && isTurnEnded(event)) {\n\t\t\tyield* Queue.offer(ended, event.data.messageId);\n\t\t}\n\t});\n\nconst finish = Effect.fn(\"CLI.finish\")(function* (state: Ref.Ref<RenderState>, columns: number) {\n\tconst rendered = yield* Ref.get(state);\n\tif (rendered.textSeen && !rendered.textEndsWithNewline) yield* writeOut(\"\\n\");\n\tyield* writeError(usage(rendered.usage, columns));\n});\n\nconst awaitMessage = Effect.fn(\"CLI.awaitMessage\")(function* (ended: Queue.Queue<string>, messageId: string) {\n\twhile ((yield* Queue.take(ended)) !== messageId) {\n\t\t// Earlier turns in the same drain are expected when a tool call continues.\n\t}\n});\n\nconst selectSandbox = Effect.fn(\"CLI.selectSandbox\")(function* (input: Sandbox.Selection) {\n\tconst selection = yield* Sandbox.resolve(input);\n\tif (selection.created && selection.info !== undefined) {\n\t\tconst id = selection.info.id;\n\t\tyield* Effect.addFinalizer(() => Effect.ignore(Sandbox.stop(id)));\n\t}\n\treturn selection.info;\n});\n\nexport default Runtime.handler(\n\tCmd.commands.run,\n\tEffect.fn(\"CLI.run\")(function* ({\n\t\tprompt,\n\t\tsession,\n\t\tcwd,\n\t\tsandboxDriver,\n\t\tsandboxProviderId,\n\t\tsandboxId,\n\t\tprovider,\n\t\tmodel,\n\t\tthinking,\n\t\tserver,\n\t}) {\n\t\tconst shared = yield* Cmd.spec;\n\t\tif (\n\t\t\tOption.isSome(session) &&\n\t\t\t(Option.isSome(cwd) ||\n\t\t\t\tOption.isSome(sandboxDriver) ||\n\t\t\t\tOption.isSome(sandboxProviderId) ||\n\t\t\t\tOption.isSome(sandboxId))\n\t\t) {\n\t\t\treturn yield* new InvalidInputError({\n\t\t\t\tmessage:\n\t\t\t\t\t\"--cwd, --sandbox-driver, --sandbox-id, and --sandbox-provider-id can only be used when creating a new session\",\n\t\t\t});\n\t\t}\n\t\tif (Option.isSome(provider) !== Option.isSome(model)) {\n\t\t\treturn yield* new InvalidInputError({ message: \"--provider and --model must be provided together\" });\n\t\t}\n\t\tif (Option.isSome(sandboxProviderId) && Option.isNone(sandboxDriver)) {\n\t\t\treturn yield* new InvalidInputError({\n\t\t\t\tmessage: \"--sandbox-provider-id requires a remote --sandbox-driver\",\n\t\t\t});\n\t\t}\n\t\tif (Option.isSome(server) && [shared.home, shared.database, shared.userConfigDir].some(Option.isSome)) {\n\t\t\treturn yield* new InvalidInputError({\n\t\t\t\tmessage: \"--home, --database, and --user-config-dir belong on codework serve when using --server\",\n\t\t\t});\n\t\t}\n\n\t\tif (Option.isSome(sandboxId) && (Option.isSome(sandboxDriver) || Option.isSome(sandboxProviderId))) {\n\t\t\treturn yield* new InvalidInputError({\n\t\t\t\tmessage: \"--sandbox-id cannot be combined with --sandbox-driver or --sandbox-provider-id\",\n\t\t\t});\n\t\t}\n\t\tconst selection: Sandbox.Selection = Option.isSome(sandboxId)\n\t\t\t? { id: Sandbox.SandboxInstance.ID.make(sandboxId.value) }\n\t\t\t: {\n\t\t\t\t\tdriver: Option.getOrElse(sandboxDriver, () => \"local\"),\n\t\t\t\t\t...(Option.isNone(sandboxProviderId) ? {} : { providerResourceId: sandboxProviderId.value }),\n\t\t\t\t};\n\n\t\t// The session's host directory, with no flag to set it: a person running a command is always\n\t\t// somewhere, and that somewhere is what they mean by \"this project\". `--cwd` is a different\n\t\t// thing entirely -- where the work runs inside the session's space, which may be a sandbox\n\t\t// on another machine.\n\t\tconst hostDir = Session.AbsolutePath.make(process.cwd());\n\n\t\tconst runtime = {\n\t\t\t...(Option.isNone(provider) || Option.isNone(model)\n\t\t\t\t? {}\n\t\t\t\t: { model: { provider: provider.value, id: model.value } }),\n\t\t\t...(Option.isNone(thinking) ? {} : { thinkingLevel: thinking.value }),\n\t\t};\n\t\tconst remote = Effect.gen(function* () {\n\t\t\tconst rpc = yield* Client.make;\n\t\t\tconst info = Option.isSome(session)\n\t\t\t\t? yield* rpc[\"session.configure\"]({ sessionId: Session.SessionSchema.ID.make(session.value), runtime })\n\t\t\t\t: yield* rpc[\"session.create\"]({\n\t\t\t\t\t\truntime,\n\t\t\t\t\t\t...(Option.isNone(cwd) ? {} : { directory: cwd.value }),\n\t\t\t\t\t\thostDir,\n\t\t\t\t\t\tsandbox: selection,\n\t\t\t\t\t});\n\t\t\tconst state = yield* Ref.make(initialRenderState);\n\t\t\tconst columns = terminalColumns();\n\t\t\tyield* writeError(\n\t\t\t\theader({\n\t\t\t\t\tsessionId: info.id,\n\t\t\t\t\tsandbox: info.sandbox?.driver ?? \"local\",\n\t\t\t\t\tdirectory: info.directory,\n\t\t\t\t\tcolumns,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (info.sandbox !== undefined) yield* writeError(`sandbox-id: ${info.sandbox.id}\\n`);\n\t\t\tyield* Client.run(rpc, { sessionId: info.id, text: prompt }, render(state)).pipe(\n\t\t\t\tEffect.onInterrupt(() =>\n\t\t\t\t\trpc[\"session.interrupt\"]({ sessionId: info.id }).pipe(Effect.timeout(\"5 seconds\"), Effect.ignore),\n\t\t\t\t),\n\t\t\t);\n\t\t\tyield* finish(state, columns);\n\t\t});\n\t\tconst program = Effect.gen(function* () {\n\t\t\tlet handle: Session.Handle;\n\t\t\tif (Option.isSome(session)) {\n\t\t\t\thandle = yield* Session.attach({ sessionId: Session.SessionSchema.ID.make(session.value), ...runtime });\n\t\t\t} else {\n\t\t\t\tconst selected = yield* selectSandbox(selection);\n\t\t\t\thandle = yield* Session.create({\n\t\t\t\t\t...runtime,\n\t\t\t\t\t...(selected === undefined ? {} : { sandbox: selected }),\n\t\t\t\t\t...(Option.isNone(cwd) ? {} : { directory: cwd.value }),\n\t\t\t\t\thostDir,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst ended = yield* Queue.unbounded<string>();\n\t\t\tconst renderState = yield* Ref.make(initialRenderState);\n\t\t\tconst printer = yield* handle\n\t\t\t\t.events()\n\t\t\t\t.pipe(Stream.runForEach(render(renderState, ended)), Effect.forkScoped({ startImmediately: true }));\n\n\t\t\tconst info = yield* handle.info;\n\t\t\tconst columns = terminalColumns();\n\t\t\tyield* writeError(\n\t\t\t\theader({\n\t\t\t\t\tsessionId: handle.id,\n\t\t\t\t\tsandbox: info.sandbox?.driver ?? \"local\",\n\t\t\t\t\tdirectory: info.directory,\n\t\t\t\t\tcolumns,\n\t\t\t\t}),\n\t\t\t);\n\t\t\t// The local command joins execution to retain typed error details.\n\t\t\tconst execution = yield* handle\n\t\t\t\t.prompt({ text: prompt, delivery: \"followUp\" })\n\t\t\t\t.pipe(Effect.andThen(handle.resume()), Effect.exit);\n\t\t\tyield* handle.wait();\n\t\t\tif (Exit.isFailure(execution)) return yield* Effect.failCause(execution.cause);\n\t\t\tconst path = yield* handle.path();\n\t\t\tconst leaf = path.at(-1);\n\t\t\tif (leaf !== undefined) yield* awaitMessage(ended, leaf.entry.id);\n\t\t\tyield* Fiber.interrupt(printer);\n\t\t\tyield* finish(renderState, columns);\n\t\t});\n\n\t\t// Scope inside the provided layer, so the run's finalizers (stopping a created sandbox) close\n\t\t// while the harness and its database are still open.\n\t\tconst execute = Effect.gen(function* () {\n\t\t\tif (Option.isSome(server))\n\t\t\t\treturn yield* remote.pipe(Effect.scoped, Effect.provide(Client.layer(server.value)));\n\t\t\t// Stdout carries only the response; harness logs go with the rest of the diagnostics.\n\t\t\treturn yield* program.pipe(\n\t\t\t\tEffect.scoped,\n\t\t\t\tEffect.provide(Harness.layer(harnessOptions(shared))),\n\t\t\t\tEffect.provideService(Logger.LogToStderr, true),\n\t\t\t);\n\t\t});\n\t\treturn yield* execute.pipe(\n\t\t\tEffect.catch((error) =>\n\t\t\t\twriteError(renderError(error)).pipe(\n\t\t\t\t\tEffect.andThen(\n\t\t\t\t\t\tEffect.sync(() => {\n\t\t\t\t\t\t\tprocess.exitCode = 1;\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t);\n\t}),\n);\n"],"mappings":"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"}