@codeworksh/cli 0.0.1-canary.10.1.g65d5c167

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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +226 -0
  3. package/acp-P_1Wqd-Z.mjs +494 -0
  4. package/acp-P_1Wqd-Z.mjs.map +1 -0
  5. package/add-DjJjtu0E.mjs +82 -0
  6. package/add-DjJjtu0E.mjs.map +1 -0
  7. package/catalog-BeNHJEEM.mjs +17 -0
  8. package/catalog-BeNHJEEM.mjs.map +1 -0
  9. package/check-CJtU790x.mjs +54 -0
  10. package/check-CJtU790x.mjs.map +1 -0
  11. package/entries-BXBULTVt.mjs +90 -0
  12. package/entries-BXBULTVt.mjs.map +1 -0
  13. package/error-CxoEKg-4.mjs +610 -0
  14. package/error-CxoEKg-4.mjs.map +1 -0
  15. package/harness-6d8TlAVk.mjs +19 -0
  16. package/harness-6d8TlAVk.mjs.map +1 -0
  17. package/index.mjs +39 -0
  18. package/index.mjs.map +1 -0
  19. package/install-CRsM-5h3.mjs +54 -0
  20. package/install-CRsM-5h3.mjs.map +1 -0
  21. package/link-orVe7_W5.mjs +41 -0
  22. package/link-orVe7_W5.mjs.map +1 -0
  23. package/list-B9t_qFIQ.mjs +77 -0
  24. package/list-B9t_qFIQ.mjs.map +1 -0
  25. package/list-C7YdESnc.mjs +30 -0
  26. package/list-C7YdESnc.mjs.map +1 -0
  27. package/login-zuKhmbS5.mjs +45 -0
  28. package/login-zuKhmbS5.mjs.map +1 -0
  29. package/logout-B0lXwmvv.mjs +29 -0
  30. package/logout-B0lXwmvv.mjs.map +1 -0
  31. package/package-KrQWL_Rw.mjs +6 -0
  32. package/package-KrQWL_Rw.mjs.map +1 -0
  33. package/package.json +54 -0
  34. package/providers-PNt4dpfv.mjs +17 -0
  35. package/providers-PNt4dpfv.mjs.map +1 -0
  36. package/refresh-FjH0oHND.mjs +17 -0
  37. package/refresh-FjH0oHND.mjs.map +1 -0
  38. package/refresh-xxKXjcRX.mjs +35 -0
  39. package/refresh-xxKXjcRX.mjs.map +1 -0
  40. package/reload-B2PxpO2s.mjs +26 -0
  41. package/reload-B2PxpO2s.mjs.map +1 -0
  42. package/remove-Deowzmc7.mjs +37 -0
  43. package/remove-Deowzmc7.mjs.map +1 -0
  44. package/run-DNRnGHYa.mjs +146 -0
  45. package/run-DNRnGHYa.mjs.map +1 -0
  46. package/runtime-BuFe9cOc.mjs +358 -0
  47. package/runtime-BuFe9cOc.mjs.map +1 -0
  48. package/serve-DfW0O2tr.mjs +300 -0
  49. package/serve-DfW0O2tr.mjs.map +1 -0
  50. package/settings-aqM_b9UE.mjs +221 -0
  51. package/settings-aqM_b9UE.mjs.map +1 -0
  52. package/shared-DN18qxOE.mjs +116 -0
  53. package/shared-DN18qxOE.mjs.map +1 -0
  54. package/status-Br21KEeh.mjs +31 -0
  55. package/status-Br21KEeh.mjs.map +1 -0
  56. package/update-qrQr-mJT.mjs +51 -0
  57. package/update-qrQr-mJT.mjs.map +1 -0
@@ -0,0 +1,494 @@
1
+ import { t as version } from "./package-KrQWL_Rw.mjs";
2
+ import { i as Cmd, t as handler } from "./runtime-BuFe9cOc.mjs";
3
+ import { i as reportFailure } from "./error-CxoEKg-4.mjs";
4
+ import { t as harnessOptions } from "./harness-6d8TlAVk.mjs";
5
+ import { Cause, DateTime, Deferred, Effect, Exit, Fiber, Logger, Option, Schema, Stdio, Stream } from "effect";
6
+ import { Model } from "@codeworksh/aikit";
7
+ import { Control, EventList, Harness, ModelCatalog, PromptSchema, Sandbox, Session, SessionStore, Settings } from "@codeworksh/harness/effect";
8
+ import * as Acp from "@agentclientprotocol/sdk";
9
+ //#region src/acp/agent.ts
10
+ /** A JSON-RPC error a handler answers a request with. */
11
+ var RequestError = class RequestError extends Schema.TaggedError()("AcpRequestError", {
12
+ code: Schema.Int,
13
+ message: Schema.String
14
+ }) {
15
+ static invalidRequest = (message) => new RequestError({
16
+ code: -32600,
17
+ message
18
+ });
19
+ static invalidParams = (message) => new RequestError({
20
+ code: -32602,
21
+ message
22
+ });
23
+ static internalError = (message) => new RequestError({
24
+ code: -32603,
25
+ message
26
+ });
27
+ static resourceNotFound = (message) => new RequestError({
28
+ code: -32002,
29
+ message
30
+ });
31
+ };
32
+ /**
33
+ * Serves an ACP agent over `stdio` until the client closes its end.
34
+ *
35
+ * Handlers run as fibers on this effect's services; a request the client cancels, or the
36
+ * connection closing, interrupts its fiber.
37
+ */
38
+ const serve$1 = Effect.fn("ACP.serve")(function* (stdio, makeHandlers) {
39
+ const context = yield* Effect.context();
40
+ const runExit = Effect.runPromiseExitWith(context);
41
+ const opened = yield* Deferred.make();
42
+ const handlers = makeHandlers({ sessionUpdate: (notification) => Deferred.await(opened).pipe(Effect.flatMap((connection) => Effect.tryPromise({
43
+ try: () => connection.client.notify(Acp.methods.client.session.update, notification),
44
+ catch: (error) => RequestError.internalError(`Failed to send session/update: ${String(error)}`)
45
+ }))) });
46
+ const toWire = (cause) => {
47
+ const error = Cause.findErrorOption(cause);
48
+ if (Option.isSome(error)) return new Acp.RequestError(error.value.code, error.value.message);
49
+ if (Cause.hasInterruptsOnly(cause)) return Acp.RequestError.requestCancelled();
50
+ return Acp.RequestError.internalError(void 0, String(Cause.squash(cause)));
51
+ };
52
+ const handle = (handler) => ({ params, signal }) => runExit(handler(params), { signal }).then((exit) => {
53
+ if (Exit.isSuccess(exit)) return exit.value;
54
+ throw toWire(exit.cause);
55
+ });
56
+ const input = yield* Stream.toReadableStreamEffect(stdio.stdin);
57
+ const output = new WritableStream({ write: (chunk) => Effect.runPromiseWith(context)(Stream.run(Stream.make(chunk), stdio.stdout())) });
58
+ const connection = Acp.agent({ name: "codework" }).onRequest("initialize", handle(handlers.initialize)).onRequest("session/new", handle(handlers.newSession)).onRequest("session/load", handle(handlers.loadSession)).onRequest("session/list", handle(handlers.listSessions)).onRequest("session/set_config_option", handle(handlers.setConfigOption)).onRequest("session/prompt", handle(handlers.prompt)).onNotification("session/cancel", handle(handlers.cancel)).connect(Acp.ndJsonStream(output, input));
59
+ yield* Deferred.succeed(opened, connection);
60
+ yield* Effect.addFinalizer(() => Effect.sync(() => connection.close()));
61
+ yield* Effect.promise(() => connection.closed);
62
+ });
63
+ //#endregion
64
+ //#region src/acp/config.ts
65
+ const MODEL = "model";
66
+ const THOUGHT_LEVEL = "thought_level";
67
+ const thinkingLabels = {
68
+ off: "Off",
69
+ minimal: "Minimal",
70
+ low: "Low",
71
+ medium: "Medium",
72
+ high: "High",
73
+ xhigh: "Extra High",
74
+ max: "Max"
75
+ };
76
+ const isThinkingLevel = (value) => Object.hasOwn(thinkingLabels, value);
77
+ /** Splits a `provider/model` option value on its first slash; model ids may contain more. */
78
+ const parseModel = (value) => {
79
+ const slash = value.indexOf("/");
80
+ if (slash <= 0 || slash === value.length - 1) return Option.none();
81
+ return Option.some({
82
+ provider: value.slice(0, slash),
83
+ id: value.slice(slash + 1)
84
+ });
85
+ };
86
+ /** The catalog a session in `hostDir` sees: generated entries plus its settings' `models`. */
87
+ const catalogFor = (hostDir) => Effect.gen(function* () {
88
+ const settings = yield* Settings.Service;
89
+ return yield* ModelCatalog.effective((yield* settings.load(hostDir)).models);
90
+ }).pipe(Effect.orElseSucceed(() => ({})));
91
+ /** The `model` and `thought_level` selectors for a session's current configuration. */
92
+ const options = Effect.fn("ACP.config.options")(function* (selection, hostDir) {
93
+ const catalog = yield* catalogFor(hostDir);
94
+ const providers = yield* ModelCatalog.available(hostDir === void 0 ? {} : { hostDir }).pipe(Effect.orElseSucceed(() => []));
95
+ const current = `${selection.provider}/${selection.model}`;
96
+ const models = providers.flatMap((provider) => Object.entries(provider.models).map(([id, info]) => ({
97
+ value: `${provider.id}/${id}`,
98
+ name: `${info.provider.name}: ${info.name}`
99
+ })));
100
+ if (!models.some((option) => option.value === current)) models.unshift({
101
+ value: current,
102
+ name: current
103
+ });
104
+ const result = [{
105
+ id: MODEL,
106
+ name: "Model",
107
+ category: "model",
108
+ type: "select",
109
+ currentValue: current,
110
+ options: models
111
+ }];
112
+ const info = catalog[selection.provider]?.[selection.model];
113
+ const levels = info === void 0 || info.reasoning === false ? [] : Model.getSupportedThinkingLevels(info);
114
+ if (levels.some((level) => level !== "off")) result.push({
115
+ id: THOUGHT_LEVEL,
116
+ name: "Thinking Effort",
117
+ category: "thought_level",
118
+ type: "select",
119
+ currentValue: levels.includes(selection.thinkingLevel) ? selection.thinkingLevel : levels[0] ?? "off",
120
+ options: levels.map((level) => ({
121
+ value: level,
122
+ name: thinkingLabels[level]
123
+ }))
124
+ });
125
+ return result;
126
+ });
127
+ /** Whether a model is in the catalog a session in `hostDir` sees. */
128
+ const known = Effect.fn("ACP.config.known")(function* (model, hostDir) {
129
+ return (yield* catalogFor(hostDir))[model.provider]?.[model.id] !== void 0;
130
+ });
131
+ //#endregion
132
+ //#region src/acp/feed.ts
133
+ const isTextDelta = Schema.is(EventList.LLMTextDelta);
134
+ const isThinkingDelta = Schema.is(EventList.LLMThinkingDelta);
135
+ const isToolStarted = Schema.is(EventList.ToolStarted);
136
+ const isToolSettled = Schema.is(EventList.ToolSettled);
137
+ const isPluginUpdated = Schema.is(EventList.PluginUpdated);
138
+ const TextContent = Schema.Struct({
139
+ type: Schema.Literal("text"),
140
+ text: Schema.String
141
+ });
142
+ const ImageContent = Schema.Struct({
143
+ type: Schema.Literal("image"),
144
+ data: Schema.String,
145
+ mimeType: Schema.String
146
+ });
147
+ const ToolResult = Schema.Struct({
148
+ content: Schema.Array(Schema.Union([TextContent, Schema.Struct({ type: Schema.Literal("image") })])),
149
+ isError: Schema.Boolean
150
+ });
151
+ const ToolCall = Schema.Struct({
152
+ type: Schema.Literal("toolCall"),
153
+ callID: Schema.String,
154
+ name: Schema.String,
155
+ arguments: Schema.Record(Schema.String, Schema.Json),
156
+ status: Schema.String,
157
+ result: Schema.optional(ToolResult)
158
+ });
159
+ const StoredPart = Schema.Union([
160
+ TextContent,
161
+ ImageContent,
162
+ Schema.Struct({
163
+ type: Schema.Literal("thinking"),
164
+ thinking: Schema.String
165
+ }),
166
+ ToolCall
167
+ ]);
168
+ const decodePart = Schema.decodeUnknownOption(Schema.fromJsonString(StoredPart));
169
+ const text = (value) => ({
170
+ type: "text",
171
+ text: value
172
+ });
173
+ const kind = (name) => name === "bash" ? "execute" : "other";
174
+ /** The command for `bash`, otherwise the tool's label or name. */
175
+ const title = (name, args, label) => name === "bash" && typeof args.command === "string" ? args.command : label ?? name;
176
+ const settled = (call) => {
177
+ const output = call.result?.content.flatMap((block) => block.type === "text" ? [block.text] : []).join("\n");
178
+ return {
179
+ sessionUpdate: "tool_call_update",
180
+ toolCallId: call.callID,
181
+ kind: kind(call.name),
182
+ status: call.status === "completed" ? "completed" : "failed",
183
+ rawInput: call.arguments,
184
+ ...call.result === void 0 ? {} : { rawOutput: call.result },
185
+ ...output ? { content: [{
186
+ type: "content",
187
+ content: text(output)
188
+ }] } : {}
189
+ };
190
+ };
191
+ /** The live `session/update` for a harness event, if the client should see one. */
192
+ const update = (event) => {
193
+ if (isTextDelta(event)) return Option.some({
194
+ sessionUpdate: "agent_message_chunk",
195
+ content: text(event.data.delta)
196
+ });
197
+ if (isThinkingDelta(event)) return Option.some({
198
+ sessionUpdate: "agent_thought_chunk",
199
+ content: text(event.data.delta)
200
+ });
201
+ if (isToolStarted(event)) return Option.some({
202
+ sessionUpdate: "tool_call",
203
+ toolCallId: event.data.callID,
204
+ title: title(event.data.name, event.data.arguments, event.data.label),
205
+ kind: kind(event.data.name),
206
+ status: "in_progress",
207
+ rawInput: event.data.arguments
208
+ });
209
+ if (isToolSettled(event)) return Option.some(settled(event.data.part));
210
+ return Option.none();
211
+ };
212
+ /**
213
+ * Text for the user about a plugin that failed to load, such as one configured but not installed.
214
+ * It belongs in the conversation because the user may never see this process's logs.
215
+ */
216
+ const notice = (event) => isPluginUpdated(event) && event.data.status === "failed" && event.data.error !== void 0 ? Option.some(event.data.error) : Option.none();
217
+ /** A notice shown to the user in the agent's message. */
218
+ const noticeUpdate = (notice) => ({
219
+ sessionUpdate: "agent_message_chunk",
220
+ content: text(`> ⚠ ${notice}\n\n`)
221
+ });
222
+ /** The `session/update`s that replay one stored entry during `session/load`. */
223
+ const replay = ({ entry, parts }) => {
224
+ if (entry.type !== "user" && entry.type !== "assistant") return [];
225
+ return parts.flatMap((row) => {
226
+ const part = decodePart(row.data);
227
+ if (Option.isNone(part)) return [];
228
+ switch (part.value.type) {
229
+ case "text": return [{
230
+ sessionUpdate: entry.type === "user" ? "user_message_chunk" : "agent_message_chunk",
231
+ content: text(part.value.text)
232
+ }];
233
+ case "image": return [{
234
+ sessionUpdate: entry.type === "user" ? "user_message_chunk" : "agent_message_chunk",
235
+ content: {
236
+ type: "image",
237
+ data: part.value.data,
238
+ mimeType: part.value.mimeType
239
+ }
240
+ }];
241
+ case "thinking": return [{
242
+ sessionUpdate: "agent_thought_chunk",
243
+ content: text(part.value.thinking)
244
+ }];
245
+ case "toolCall": return [{
246
+ sessionUpdate: "tool_call",
247
+ toolCallId: part.value.callID,
248
+ title: title(part.value.name, part.value.arguments),
249
+ kind: kind(part.value.name),
250
+ status: "in_progress",
251
+ rawInput: part.value.arguments
252
+ }, settled(part.value)];
253
+ }
254
+ });
255
+ };
256
+ //#endregion
257
+ //#region src/acp/handlers.ts
258
+ const PAGE_SIZE = 50;
259
+ const isRequestError = Schema.is(RequestError);
260
+ const isNotFound = Schema.is(SessionStore.SessionNotFoundError);
261
+ const isConflict = Schema.is(Control.PromptConflictError);
262
+ const isInvalidPrompt = Schema.is(PromptSchema.InvalidPromptError);
263
+ const isLLMEnded = Schema.is(EventList.LLMEnded);
264
+ const isSucceeded = Schema.is(EventList.ExecutionSucceeded);
265
+ const isFailed = Schema.is(EventList.ExecutionFailed);
266
+ const isInterrupted = Schema.is(EventList.ExecutionInterrupted);
267
+ const isSettled = (event) => isSucceeded(event) || isFailed(event) || isInterrupted(event);
268
+ /** Harness failures as JSON-RPC errors; handlers raise protocol-level ones directly. */
269
+ const toRequestError = (error) => {
270
+ if (isRequestError(error)) return error;
271
+ if (isNotFound(error)) return RequestError.resourceNotFound(`Session not found: ${error.sessionId}`);
272
+ if (isConflict(error)) return RequestError.invalidRequest(error.message);
273
+ if (isInvalidPrompt(error)) return RequestError.invalidParams(error.message);
274
+ return RequestError.internalError(error.message);
275
+ };
276
+ /**
277
+ * Prompt content as harness prompt parts, in order. Text, embedded context and images are
278
+ * advertised; anything else is rejected. Adjacent text joins into one part. The harness checks
279
+ * the images.
280
+ */
281
+ const promptParts = Effect.fnUntraced(function* (blocks) {
282
+ const parts = [];
283
+ const add = (part) => {
284
+ const last = parts.at(-1);
285
+ if (part.type === "text" && last?.type === "text") parts[parts.length - 1] = {
286
+ ...last,
287
+ text: `${last.text}\n\n${part.text}`
288
+ };
289
+ else parts.push(part);
290
+ };
291
+ for (const block of blocks) switch (block.type) {
292
+ case "text":
293
+ add({
294
+ type: "text",
295
+ text: block.text
296
+ });
297
+ break;
298
+ case "resource_link":
299
+ add({
300
+ type: "text",
301
+ text: `[${block.name}](${block.uri})`
302
+ });
303
+ break;
304
+ case "image":
305
+ add({
306
+ type: "image",
307
+ data: block.data,
308
+ mimeType: block.mimeType
309
+ });
310
+ break;
311
+ case "resource":
312
+ if ("text" in block.resource) add({
313
+ type: "text",
314
+ text: `\`\`\`${block.resource.uri}\n${block.resource.text}\n\`\`\``
315
+ });
316
+ else if (block.resource.mimeType?.startsWith("image/")) add({
317
+ type: "image",
318
+ data: block.resource.blob,
319
+ mimeType: block.resource.mimeType
320
+ });
321
+ else return yield* RequestError.invalidParams(`Unsupported binary resource: ${block.resource.uri}`);
322
+ break;
323
+ default: return yield* RequestError.invalidParams(`Unsupported prompt content: ${block.type}`);
324
+ }
325
+ return parts;
326
+ });
327
+ const sessionId = (id) => Session.SessionSchema.ID.make(id);
328
+ const make = Effect.gen(function* () {
329
+ const control = yield* Control.Service;
330
+ const sessions = yield* SessionStore.Service;
331
+ const context = yield* Effect.context();
332
+ const running = /* @__PURE__ */ new Set();
333
+ const found = Effect.fn("ACP.found")(function* (id) {
334
+ const row = yield* sessions.get(sessionId(id));
335
+ if (Option.isNone(row)) return yield* new SessionStore.SessionNotFoundError({ sessionId: sessionId(id) });
336
+ return row.value;
337
+ });
338
+ return (client) => {
339
+ const run = (effect) => effect.pipe(Effect.provide(context), Effect.mapError(toRequestError));
340
+ return {
341
+ initialize: () => Effect.succeed({
342
+ protocolVersion: 1,
343
+ agentInfo: {
344
+ name: "codework",
345
+ version
346
+ },
347
+ agentCapabilities: {
348
+ loadSession: true,
349
+ promptCapabilities: {
350
+ embeddedContext: true,
351
+ image: true
352
+ },
353
+ sessionCapabilities: { list: {} }
354
+ }
355
+ }),
356
+ newSession: ({ cwd }) => run(Effect.gen(function* () {
357
+ const handle = yield* Session.create({
358
+ directory: cwd,
359
+ hostDir: cwd
360
+ });
361
+ const current = yield* Session.configuration(handle.id);
362
+ return {
363
+ sessionId: handle.id,
364
+ configOptions: yield* options(current, cwd)
365
+ };
366
+ })),
367
+ loadSession: ({ sessionId: id }) => run(Effect.gen(function* () {
368
+ yield* Session.attach({ sessionId: sessionId(id) });
369
+ const row = yield* found(id);
370
+ const hostDir = Option.getOrUndefined(row.hostDir);
371
+ const current = yield* Session.configuration(row.id);
372
+ for (const entry of yield* sessions.path(sessionId(id))) for (const update of replay(entry)) yield* client.sessionUpdate({
373
+ sessionId: id,
374
+ update
375
+ });
376
+ return { configOptions: yield* options(current, hostDir) };
377
+ })),
378
+ listSessions: ({ cwd, cursor }) => run(Effect.gen(function* () {
379
+ const rows = (yield* sessions.list()).filter((row) => cwd == null || Option.getOrUndefined(row.hostDir) === cwd).sort((a, b) => DateTime.Order(b.updatedAt ?? b.createdAt, a.updatedAt ?? a.createdAt));
380
+ const offset = cursor == null ? 0 : Number(cursor);
381
+ if (!Number.isSafeInteger(offset) || offset < 0) return yield* RequestError.invalidParams(`Invalid cursor: ${cursor}`);
382
+ const next = offset + PAGE_SIZE;
383
+ return {
384
+ sessions: rows.slice(offset, next).map((row) => ({
385
+ sessionId: row.id,
386
+ cwd: Option.getOrElse(row.hostDir, () => row.directory),
387
+ title: row.title,
388
+ updatedAt: DateTime.formatIso(row.updatedAt ?? row.createdAt)
389
+ })),
390
+ ...next < rows.length ? { nextCursor: String(next) } : {}
391
+ };
392
+ })),
393
+ setConfigOption: (request) => run(Effect.gen(function* () {
394
+ const row = yield* found(request.sessionId);
395
+ const hostDir = Option.getOrUndefined(row.hostDir);
396
+ const value = String(request.value);
397
+ if (request.configId === "model") {
398
+ const model = Option.getOrUndefined(parseModel(value));
399
+ if (model === void 0 || !(yield* known(model, hostDir))) return yield* RequestError.invalidParams(`Unknown model: ${value}`);
400
+ yield* Session.attach({
401
+ sessionId: row.id,
402
+ model
403
+ });
404
+ } else if (request.configId === "thought_level") {
405
+ if (!isThinkingLevel(value)) return yield* RequestError.invalidParams(`Unknown thinking level: ${value}`);
406
+ yield* Session.attach({
407
+ sessionId: row.id,
408
+ thinkingLevel: value
409
+ });
410
+ } else return yield* RequestError.invalidParams(`Unknown config option: ${request.configId}`);
411
+ return { configOptions: yield* options(yield* Session.configuration(row.id), hostDir) };
412
+ })),
413
+ prompt: ({ sessionId: id, prompt }) => run(Effect.gen(function* () {
414
+ const parts = yield* promptParts(prompt);
415
+ const handle = Option.getOrUndefined(yield* Session.get(sessionId(id)));
416
+ if (handle === void 0) return yield* new SessionStore.SessionNotFoundError({ sessionId: sessionId(id) });
417
+ if (running.has(id)) return yield* RequestError.invalidRequest("A prompt is already running for this session");
418
+ running.add(id);
419
+ yield* Effect.addFinalizer(() => Effect.sync(() => running.delete(id)));
420
+ let reason;
421
+ const notices = /* @__PURE__ */ new Set();
422
+ const settled = yield* handle.events().pipe(Stream.tap((event) => {
423
+ if (isLLMEnded(event)) reason = event.data.reason;
424
+ let update$1 = update(event);
425
+ const notice$1 = notice(event);
426
+ if (Option.isSome(notice$1) && !notices.has(notice$1.value)) {
427
+ notices.add(notice$1.value);
428
+ update$1 = Option.some(noticeUpdate(notice$1.value));
429
+ }
430
+ return Option.match(update$1, {
431
+ onNone: () => Effect.void,
432
+ onSome: (update) => client.sessionUpdate({
433
+ sessionId: id,
434
+ update
435
+ }).pipe(Effect.ignore)
436
+ });
437
+ }), Stream.filter(isSettled), Stream.runHead, Effect.forkScoped({ startImmediately: true }));
438
+ const before = (yield* handle.info).title;
439
+ yield* handle.run({ parts });
440
+ const end = yield* Fiber.join(settled);
441
+ const { title } = yield* handle.info;
442
+ if (title !== before) yield* client.sessionUpdate({
443
+ sessionId: id,
444
+ update: {
445
+ sessionUpdate: "session_info_update",
446
+ title
447
+ }
448
+ }).pipe(Effect.ignore);
449
+ if (Option.isNone(end) || isInterrupted(end.value)) return { stopReason: "cancelled" };
450
+ if (isFailed(end.value)) return yield* RequestError.internalError(end.value.data.error.message);
451
+ return { stopReason: reason === "length" ? "max_tokens" : "end_turn" };
452
+ }).pipe(Effect.scoped)),
453
+ cancel: ({ sessionId: id }) => control.interrupt(sessionId(id), { reason: "user" }).pipe(Effect.asVoid)
454
+ };
455
+ };
456
+ });
457
+ //#endregion
458
+ //#region src/acp/server.ts
459
+ const shutdown = Effect.gen(function* () {
460
+ const control = yield* Control.Service;
461
+ yield* Effect.forEach(yield* control.active, (id) => control.interrupt(id, {
462
+ reason: "shutdown",
463
+ awaitSettlement: true
464
+ }).pipe(Effect.timeout("10 seconds"), Effect.ignore), {
465
+ concurrency: "unbounded",
466
+ discard: true
467
+ });
468
+ const managed = (yield* Sandbox.list()).filter((info) => info.ownership === "managed");
469
+ yield* Effect.forEach(managed, (info) => Sandbox.stop(info.id).pipe(Effect.timeout("10 seconds"), Effect.catchCause((cause) => Effect.logError("Failed to stop managed sandbox during ACP shutdown", cause).pipe(Effect.annotateLogs({ sandboxInstanceId: info.id })))), {
470
+ concurrency: "unbounded",
471
+ discard: true
472
+ });
473
+ });
474
+ /**
475
+ * Serves ACP v1 on stdio until the client disconnects.
476
+ *
477
+ * stdout carries the protocol, so logs go to stderr. The reference is set outside the harness layer
478
+ * so the fibers it forks (turns, plugin loads) inherit it too.
479
+ */
480
+ const serve = (options) => Effect.gen(function* () {
481
+ yield* Effect.addFinalizer(() => shutdown.pipe(Effect.ignore));
482
+ const handlers = yield* make;
483
+ yield* serve$1(yield* Stdio.Stdio, handlers);
484
+ }).pipe(Effect.scoped, Effect.provide(Harness.layer(options)), Effect.provideService(Logger.LogToStderr, true));
485
+ //#endregion
486
+ //#region src/cli/cmd/handlers/acp.ts
487
+ var acp_default = handler(Cmd.commands.acp, Effect.fn("CLI.acp")(function* () {
488
+ const shared = yield* Cmd.spec;
489
+ return yield* serve(harnessOptions(shared)).pipe(Effect.catch(reportFailure));
490
+ }));
491
+ //#endregion
492
+ export { acp_default as default };
493
+
494
+ //# sourceMappingURL=acp-P_1Wqd-Z.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acp-P_1Wqd-Z.mjs","names":["serve","Agent.RequestError","pkg.version","Config.options","Feed.replay","Config.parseModel","Config.known","Config.isThinkingLevel","update","Feed.update","notice","Feed.notice","Feed.noticeUpdate","Handlers.make","Agent.serve","Runtime.handler","Server.serve"],"sources":["../../src/acp/agent.ts","../../src/acp/config.ts","../../src/acp/feed.ts","../../src/acp/handlers.ts","../../src/acp/server.ts","../../src/cli/cmd/handlers/acp.ts"],"sourcesContent":["import * as Acp from \"@agentclientprotocol/sdk\";\nimport { Cause, Deferred, Effect, Exit, Option, Schema, type Scope, type Stdio, Stream } from \"effect\";\n\n/** A JSON-RPC error a handler answers a request with. */\nexport class RequestError extends Schema.TaggedError<RequestError>()(\"AcpRequestError\", {\n\tcode: Schema.Int,\n\tmessage: Schema.String,\n}) {\n\tstatic invalidRequest = (message: string) => new RequestError({ code: -32600, message });\n\tstatic invalidParams = (message: string) => new RequestError({ code: -32602, message });\n\tstatic internalError = (message: string) => new RequestError({ code: -32603, message });\n\tstatic resourceNotFound = (message: string) => new RequestError({ code: -32002, message });\n}\n\ntype Handler<Request, Response> = (request: Request) => Effect.Effect<Response, RequestError>;\n\n/** Calls the agent makes to the connected client. */\nexport interface Client {\n\treadonly sessionUpdate: (notification: Acp.SessionNotification) => Effect.Effect<void, RequestError>;\n}\n\nexport interface Handlers {\n\treadonly initialize: Handler<Acp.InitializeRequest, Acp.InitializeResponse>;\n\treadonly newSession: Handler<Acp.NewSessionRequest, Acp.NewSessionResponse>;\n\t/** Must replay the session's history through `Client.sessionUpdate` before it returns. */\n\treadonly loadSession: Handler<Acp.LoadSessionRequest, Acp.LoadSessionResponse>;\n\treadonly listSessions: Handler<Acp.ListSessionsRequest, Acp.ListSessionsResponse>;\n\treadonly setConfigOption: Handler<Acp.SetSessionConfigOptionRequest, Acp.SetSessionConfigOptionResponse>;\n\treadonly prompt: Handler<Acp.PromptRequest, Acp.PromptResponse>;\n\treadonly cancel: (notification: Acp.CancelNotification) => Effect.Effect<void>;\n}\n\n/**\n * Serves an ACP agent over `stdio` until the client closes its end.\n *\n * Handlers run as fibers on this effect's services; a request the client cancels, or the\n * connection closing, interrupts its fiber.\n */\nexport const serve = Effect.fn(\"ACP.serve\")(function* (\n\tstdio: Stdio.Stdio,\n\tmakeHandlers: (client: Client) => Handlers,\n): Effect.fn.Return<void, never, Scope.Scope> {\n\tconst context = yield* Effect.context<never>();\n\tconst runExit = Effect.runPromiseExitWith(context);\n\tconst opened = yield* Deferred.make<Acp.AgentConnection>();\n\n\tconst handlers = makeHandlers({\n\t\tsessionUpdate: (notification) =>\n\t\t\tDeferred.await(opened).pipe(\n\t\t\t\tEffect.flatMap((connection) =>\n\t\t\t\t\tEffect.tryPromise({\n\t\t\t\t\t\ttry: () => connection.client.notify(Acp.methods.client.session.update, notification),\n\t\t\t\t\t\tcatch: (error) => RequestError.internalError(`Failed to send session/update: ${String(error)}`),\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t});\n\n\t// A JSON-RPC answer for a handler that didn't succeed; the SDK sends what `handle` throws.\n\tconst toWire = (cause: Cause.Cause<RequestError>): Acp.RequestError => {\n\t\tconst error = Cause.findErrorOption(cause);\n\t\tif (Option.isSome(error)) return new Acp.RequestError(error.value.code, error.value.message);\n\t\tif (Cause.hasInterruptsOnly(cause)) return Acp.RequestError.requestCancelled();\n\t\treturn Acp.RequestError.internalError(undefined, String(Cause.squash(cause)));\n\t};\n\tconst handle =\n\t\t<Params, A>(handler: (params: Params) => Effect.Effect<A, RequestError>) =>\n\t\t({ params, signal }: { readonly params: Params; readonly signal: AbortSignal }): Promise<A> =>\n\t\t\trunExit(handler(params), { signal }).then((exit) => {\n\t\t\t\tif (Exit.isSuccess(exit)) return exit.value;\n\t\t\t\tthrow toWire(exit.cause);\n\t\t\t});\n\n\tconst input = yield* Stream.toReadableStreamEffect(stdio.stdin);\n\tconst output = new WritableStream<Uint8Array>({\n\t\twrite: (chunk) => Effect.runPromiseWith(context)(Stream.run(Stream.make(chunk), stdio.stdout())),\n\t});\n\n\tconst connection = Acp.agent({ name: \"codework\" })\n\t\t.onRequest(\"initialize\", handle(handlers.initialize))\n\t\t.onRequest(\"session/new\", handle(handlers.newSession))\n\t\t.onRequest(\"session/load\", handle(handlers.loadSession))\n\t\t.onRequest(\"session/list\", handle(handlers.listSessions))\n\t\t.onRequest(\"session/set_config_option\", handle(handlers.setConfigOption))\n\t\t.onRequest(\"session/prompt\", handle(handlers.prompt))\n\t\t.onNotification(\"session/cancel\", handle(handlers.cancel))\n\t\t.connect(Acp.ndJsonStream(output, input));\n\tyield* Deferred.succeed(opened, connection);\n\tyield* Effect.addFinalizer(() => Effect.sync(() => connection.close()));\n\tyield* Effect.promise(() => connection.closed);\n});\n\nexport * as Agent from \"./agent.ts\";\n","import type * as Acp from \"@agentclientprotocol/sdk\";\nimport { Model } from \"@codeworksh/aikit\";\nimport { ModelCatalog, Settings, type State } from \"@codeworksh/harness/effect\";\nimport { Effect, Option } from \"effect\";\n\nexport const MODEL = \"model\";\nexport const THOUGHT_LEVEL = \"thought_level\";\n\nconst thinkingLabels: Record<Model.ThinkingLevel, string> = {\n\toff: \"Off\",\n\tminimal: \"Minimal\",\n\tlow: \"Low\",\n\tmedium: \"Medium\",\n\thigh: \"High\",\n\txhigh: \"Extra High\",\n\tmax: \"Max\",\n};\n\nexport const isThinkingLevel = (value: string): value is Model.ThinkingLevel => Object.hasOwn(thinkingLabels, value);\n\n/** Splits a `provider/model` option value on its first slash; model ids may contain more. */\nexport const parseModel = (value: string): Option.Option<{ readonly provider: string; readonly id: string }> => {\n\tconst slash = value.indexOf(\"/\");\n\tif (slash <= 0 || slash === value.length - 1) return Option.none();\n\treturn Option.some({ provider: value.slice(0, slash), id: value.slice(slash + 1) });\n};\n\n/** The catalog a session in `hostDir` sees: generated entries plus its settings' `models`. */\nconst catalogFor = (hostDir: string | undefined) =>\n\tEffect.gen(function* () {\n\t\tconst settings = yield* Settings.Service;\n\t\treturn yield* ModelCatalog.effective((yield* settings.load(hostDir)).models);\n\t}).pipe(Effect.orElseSucceed((): Model.BuiltInModels => ({})));\n\n/** The `model` and `thought_level` selectors for a session's current configuration. */\nexport const options = Effect.fn(\"ACP.config.options\")(function* (\n\tselection: State.Configuration,\n\thostDir: string | undefined,\n) {\n\tconst catalog = yield* catalogFor(hostDir);\n\t// Providers the harness has credentials for; the current model stays selectable even if not.\n\tconst providers = yield* ModelCatalog.available(hostDir === undefined ? {} : { hostDir }).pipe(\n\t\tEffect.orElseSucceed(() => []),\n\t);\n\n\tconst current = `${selection.provider}/${selection.model}`;\n\tconst models = providers.flatMap((provider) =>\n\t\tObject.entries(provider.models).map(([id, info]) => ({\n\t\t\tvalue: `${provider.id}/${id}`,\n\t\t\tname: `${info.provider.name}: ${info.name}`,\n\t\t})),\n\t);\n\tif (!models.some((option) => option.value === current)) models.unshift({ value: current, name: current });\n\n\tconst result: Array<Acp.SessionConfigOption> = [\n\t\t{ id: MODEL, name: \"Model\", category: \"model\", type: \"select\", currentValue: current, options: models },\n\t];\n\n\tconst info = catalog[selection.provider]?.[selection.model];\n\tconst levels = info === undefined || info.reasoning === false ? [] : Model.getSupportedThinkingLevels(info);\n\tif (levels.some((level) => level !== \"off\")) {\n\t\tresult.push({\n\t\t\tid: THOUGHT_LEVEL,\n\t\t\tname: \"Thinking Effort\",\n\t\t\tcategory: \"thought_level\",\n\t\t\ttype: \"select\",\n\t\t\tcurrentValue: levels.includes(selection.thinkingLevel) ? selection.thinkingLevel : (levels[0] ?? \"off\"),\n\t\t\toptions: levels.map((level) => ({ value: level, name: thinkingLabels[level] })),\n\t\t});\n\t}\n\treturn result;\n});\n\n/** Whether a model is in the catalog a session in `hostDir` sees. */\nexport const known = Effect.fn(\"ACP.config.known\")(function* (\n\tmodel: { readonly provider: string; readonly id: string },\n\thostDir: string | undefined,\n) {\n\tconst catalog = yield* catalogFor(hostDir);\n\treturn catalog[model.provider]?.[model.id] !== undefined;\n});\n\nexport * as Config from \"./config.ts\";\n","import type * as Acp from \"@agentclientprotocol/sdk\";\nimport { EventList, type EventSchema, type SessionStore } from \"@codeworksh/harness/effect\";\nimport { Option, Schema } from \"effect\";\n\nconst isTextDelta = Schema.is(EventList.LLMTextDelta);\nconst isThinkingDelta = Schema.is(EventList.LLMThinkingDelta);\nconst isToolStarted = Schema.is(EventList.ToolStarted);\nconst isToolSettled = Schema.is(EventList.ToolSettled);\nconst isPluginUpdated = Schema.is(EventList.PluginUpdated);\n\nconst TextContent = Schema.Struct({ type: Schema.Literal(\"text\"), text: Schema.String });\nconst ImageContent = Schema.Struct({ type: Schema.Literal(\"image\"), data: Schema.String, mimeType: Schema.String });\nconst ToolResult = Schema.Struct({\n\tcontent: Schema.Array(Schema.Union([TextContent, Schema.Struct({ type: Schema.Literal(\"image\") })])),\n\tisError: Schema.Boolean,\n});\nconst ToolCall = Schema.Struct({\n\ttype: Schema.Literal(\"toolCall\"),\n\tcallID: Schema.String,\n\tname: Schema.String,\n\targuments: Schema.Record(Schema.String, Schema.Json),\n\tstatus: Schema.String,\n\tresult: Schema.optional(ToolResult),\n});\nconst StoredPart = Schema.Union([\n\tTextContent,\n\tImageContent,\n\tSchema.Struct({ type: Schema.Literal(\"thinking\"), thinking: Schema.String }),\n\tToolCall,\n]);\nconst decodePart = Schema.decodeUnknownOption(Schema.fromJsonString(StoredPart));\n\ntype ToolCall = typeof ToolCall.Type;\n\nconst text = (value: string): Acp.ContentBlock => ({ type: \"text\", text: value });\n\n// The kind comes from the tool's name. Only `bash` ships built in; plugin tools report `other`.\nconst kind = (name: string): Acp.ToolKind => (name === \"bash\" ? \"execute\" : \"other\");\n\n/** The command for `bash`, otherwise the tool's label or name. */\nconst title = (name: string, args: Readonly<Record<string, unknown>>, label?: string): string =>\n\tname === \"bash\" && typeof args.command === \"string\" ? args.command : (label ?? name);\n\nconst settled = (call: Pick<ToolCall, \"callID\" | \"name\" | \"arguments\" | \"status\" | \"result\">): Acp.SessionUpdate => {\n\tconst output = call.result?.content.flatMap((block) => (block.type === \"text\" ? [block.text] : [])).join(\"\\n\");\n\treturn {\n\t\tsessionUpdate: \"tool_call_update\",\n\t\ttoolCallId: call.callID,\n\t\tkind: kind(call.name),\n\t\tstatus: call.status === \"completed\" ? \"completed\" : \"failed\",\n\t\trawInput: call.arguments,\n\t\t...(call.result === undefined ? {} : { rawOutput: call.result }),\n\t\t...(output ? { content: [{ type: \"content\", content: text(output) }] } : {}),\n\t};\n};\n\n/** The live `session/update` for a harness event, if the client should see one. */\nexport const update = (event: EventSchema.Payload): Option.Option<Acp.SessionUpdate> => {\n\tif (isTextDelta(event)) {\n\t\treturn Option.some({ sessionUpdate: \"agent_message_chunk\", content: text(event.data.delta) });\n\t}\n\tif (isThinkingDelta(event)) {\n\t\treturn Option.some({ sessionUpdate: \"agent_thought_chunk\", content: text(event.data.delta) });\n\t}\n\tif (isToolStarted(event)) {\n\t\treturn Option.some({\n\t\t\tsessionUpdate: \"tool_call\",\n\t\t\ttoolCallId: event.data.callID,\n\t\t\ttitle: title(event.data.name, event.data.arguments, event.data.label),\n\t\t\tkind: kind(event.data.name),\n\t\t\tstatus: \"in_progress\",\n\t\t\trawInput: event.data.arguments,\n\t\t});\n\t}\n\tif (isToolSettled(event)) return Option.some(settled(event.data.part));\n\treturn Option.none();\n};\n\n/**\n * Text for the user about a plugin that failed to load, such as one configured but not installed.\n * It belongs in the conversation because the user may never see this process's logs.\n */\nexport const notice = (event: EventSchema.Payload): Option.Option<string> =>\n\tisPluginUpdated(event) && event.data.status === \"failed\" && event.data.error !== undefined\n\t\t? Option.some(event.data.error)\n\t\t: Option.none();\n\n/** A notice shown to the user in the agent's message. */\nexport const noticeUpdate = (notice: string): Acp.SessionUpdate => ({\n\tsessionUpdate: \"agent_message_chunk\",\n\tcontent: text(`> ⚠ ${notice}\\n\\n`),\n});\n\n/** The `session/update`s that replay one stored entry during `session/load`. */\nexport const replay = ({ entry, parts }: SessionStore.HydratedEntry): ReadonlyArray<Acp.SessionUpdate> => {\n\tif (entry.type !== \"user\" && entry.type !== \"assistant\") return [];\n\treturn parts.flatMap((row): ReadonlyArray<Acp.SessionUpdate> => {\n\t\tconst part = decodePart(row.data);\n\t\tif (Option.isNone(part)) return [];\n\t\tswitch (part.value.type) {\n\t\t\tcase \"text\":\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tsessionUpdate: entry.type === \"user\" ? \"user_message_chunk\" : \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: text(part.value.text),\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\tcase \"image\":\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tsessionUpdate: entry.type === \"user\" ? \"user_message_chunk\" : \"agent_message_chunk\",\n\t\t\t\t\t\tcontent: { type: \"image\", data: part.value.data, mimeType: part.value.mimeType },\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\tcase \"thinking\":\n\t\t\t\treturn [{ sessionUpdate: \"agent_thought_chunk\", content: text(part.value.thinking) }];\n\t\t\tcase \"toolCall\":\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tsessionUpdate: \"tool_call\",\n\t\t\t\t\t\ttoolCallId: part.value.callID,\n\t\t\t\t\t\ttitle: title(part.value.name, part.value.arguments),\n\t\t\t\t\t\tkind: kind(part.value.name),\n\t\t\t\t\t\tstatus: \"in_progress\",\n\t\t\t\t\t\trawInput: part.value.arguments,\n\t\t\t\t\t},\n\t\t\t\t\tsettled(part.value),\n\t\t\t\t];\n\t\t}\n\t});\n};\n\nexport * as Feed from \"./feed.ts\";\n","import type * as Acp from \"@agentclientprotocol/sdk\";\nimport {\n\tControl,\n\tEventList,\n\ttype EventSchema,\n\ttype Harness,\n\tPromptSchema,\n\tSession,\n\tSessionStore,\n} from \"@codeworksh/harness/effect\";\nimport { DateTime, Effect, Fiber, type Layer, Option, Schema, Stream } from \"effect\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\nimport { Agent } from \"./agent.ts\";\nimport { Config } from \"./config.ts\";\nimport { Feed } from \"./feed.ts\";\n\nconst PAGE_SIZE = 50;\n\nconst isRequestError = Schema.is(Agent.RequestError);\nconst isNotFound = Schema.is(SessionStore.SessionNotFoundError);\nconst isConflict = Schema.is(Control.PromptConflictError);\nconst isInvalidPrompt = Schema.is(PromptSchema.InvalidPromptError);\nconst isLLMEnded = Schema.is(EventList.LLMEnded);\nconst isSucceeded = Schema.is(EventList.ExecutionSucceeded);\nconst isFailed = Schema.is(EventList.ExecutionFailed);\nconst isInterrupted = Schema.is(EventList.ExecutionInterrupted);\nconst isSettled = (event: EventSchema.Payload) => isSucceeded(event) || isFailed(event) || isInterrupted(event);\n\n/** Harness failures as JSON-RPC errors; handlers raise protocol-level ones directly. */\nconst toRequestError = (error: { readonly message: string }): Agent.RequestError => {\n\tif (isRequestError(error)) return error;\n\tif (isNotFound(error)) return Agent.RequestError.resourceNotFound(`Session not found: ${error.sessionId}`);\n\tif (isConflict(error)) return Agent.RequestError.invalidRequest(error.message);\n\tif (isInvalidPrompt(error)) return Agent.RequestError.invalidParams(error.message);\n\treturn Agent.RequestError.internalError(error.message);\n};\n\n/**\n * Prompt content as harness prompt parts, in order. Text, embedded context and images are\n * advertised; anything else is rejected. Adjacent text joins into one part. The harness checks\n * the images.\n */\nconst promptParts = Effect.fnUntraced(function* (blocks: ReadonlyArray<Acp.ContentBlock>) {\n\tconst parts: Array<PromptSchema.Part> = [];\n\tconst add = (part: PromptSchema.Part) => {\n\t\tconst last = parts.at(-1);\n\t\tif (part.type === \"text\" && last?.type === \"text\")\n\t\t\tparts[parts.length - 1] = { ...last, text: `${last.text}\\n\\n${part.text}` };\n\t\telse parts.push(part);\n\t};\n\tfor (const block of blocks) {\n\t\tswitch (block.type) {\n\t\t\tcase \"text\":\n\t\t\t\tadd({ type: \"text\", text: block.text });\n\t\t\t\tbreak;\n\t\t\tcase \"resource_link\":\n\t\t\t\tadd({ type: \"text\", text: `[${block.name}](${block.uri})` });\n\t\t\t\tbreak;\n\t\t\tcase \"image\":\n\t\t\t\tadd({ type: \"image\", data: block.data, mimeType: block.mimeType });\n\t\t\t\tbreak;\n\t\t\tcase \"resource\":\n\t\t\t\tif (\"text\" in block.resource) {\n\t\t\t\t\tadd({ type: \"text\", text: `\\`\\`\\`${block.resource.uri}\\n${block.resource.text}\\n\\`\\`\\`` });\n\t\t\t\t} else if (block.resource.mimeType?.startsWith(\"image/\")) {\n\t\t\t\t\tadd({ type: \"image\", data: block.resource.blob, mimeType: block.resource.mimeType });\n\t\t\t\t} else {\n\t\t\t\t\treturn yield* Agent.RequestError.invalidParams(`Unsupported binary resource: ${block.resource.uri}`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn yield* Agent.RequestError.invalidParams(`Unsupported prompt content: ${block.type}`);\n\t\t}\n\t}\n\treturn parts;\n});\n\nconst sessionId = (id: string) => Session.SessionSchema.ID.make(id);\n\ntype Services = Layer.Success<ReturnType<typeof Harness.layer>>;\n\nexport const make = Effect.gen(function* () {\n\tconst control = yield* Control.Service;\n\tconst sessions = yield* SessionStore.Service;\n\t// Handlers run on the agent's fibers, outside this layer; they carry the harness with them.\n\tconst context = yield* Effect.context<Services>();\n\n\tconst running = new Set<string>();\n\n\tconst found = Effect.fn(\"ACP.found\")(function* (id: string) {\n\t\tconst row = yield* sessions.get(sessionId(id));\n\t\tif (Option.isNone(row)) return yield* new SessionStore.SessionNotFoundError({ sessionId: sessionId(id) });\n\t\treturn row.value;\n\t});\n\n\treturn (client: Agent.Client): Agent.Handlers => {\n\t\tconst run = <A, E extends { readonly message: string }>(effect: Effect.Effect<A, E, Services>) =>\n\t\t\teffect.pipe(Effect.provide(context), Effect.mapError(toRequestError));\n\n\t\treturn {\n\t\t\tinitialize: () =>\n\t\t\t\tEffect.succeed({\n\t\t\t\t\tprotocolVersion: 1,\n\t\t\t\t\tagentInfo: { name: \"codework\", version: pkg.version },\n\t\t\t\t\tagentCapabilities: {\n\t\t\t\t\t\tloadSession: true,\n\t\t\t\t\t\tpromptCapabilities: { embeddedContext: true, image: true },\n\t\t\t\t\t\tsessionCapabilities: { list: {} },\n\t\t\t\t\t},\n\t\t\t\t}),\n\n\t\t\tnewSession: ({ cwd }) =>\n\t\t\t\trun(\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst handle = yield* Session.create({ directory: cwd, hostDir: cwd });\n\t\t\t\t\t\tconst current = yield* Session.configuration(handle.id);\n\t\t\t\t\t\treturn { sessionId: handle.id, configOptions: yield* Config.options(current, cwd) };\n\t\t\t\t\t}),\n\t\t\t\t),\n\n\t\t\tloadSession: ({ sessionId: id }) =>\n\t\t\t\trun(\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tyield* Session.attach({ sessionId: sessionId(id) });\n\t\t\t\t\t\tconst row = yield* found(id);\n\t\t\t\t\t\tconst hostDir = Option.getOrUndefined(row.hostDir);\n\t\t\t\t\t\tconst current = yield* Session.configuration(row.id);\n\t\t\t\t\t\tfor (const entry of yield* sessions.path(sessionId(id))) {\n\t\t\t\t\t\t\tfor (const update of Feed.replay(entry)) {\n\t\t\t\t\t\t\t\tyield* client.sessionUpdate({ sessionId: id, update });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { configOptions: yield* Config.options(current, hostDir) };\n\t\t\t\t\t}),\n\t\t\t\t),\n\n\t\t\tlistSessions: ({ cwd, cursor }) =>\n\t\t\t\trun(\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst rows = (yield* sessions.list())\n\t\t\t\t\t\t\t.filter((row) => cwd == null || Option.getOrUndefined(row.hostDir) === cwd)\n\t\t\t\t\t\t\t.sort((a, b) => DateTime.Order(b.updatedAt ?? b.createdAt, a.updatedAt ?? a.createdAt));\n\t\t\t\t\t\tconst offset = cursor == null ? 0 : Number(cursor);\n\t\t\t\t\t\tif (!Number.isSafeInteger(offset) || offset < 0) {\n\t\t\t\t\t\t\treturn yield* Agent.RequestError.invalidParams(`Invalid cursor: ${cursor}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst next = offset + PAGE_SIZE;\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tsessions: rows.slice(offset, next).map((row) => ({\n\t\t\t\t\t\t\t\tsessionId: row.id,\n\t\t\t\t\t\t\t\tcwd: Option.getOrElse(row.hostDir, () => row.directory),\n\t\t\t\t\t\t\t\ttitle: row.title,\n\t\t\t\t\t\t\t\tupdatedAt: DateTime.formatIso(row.updatedAt ?? row.createdAt),\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t...(next < rows.length ? { nextCursor: String(next) } : {}),\n\t\t\t\t\t\t};\n\t\t\t\t\t}),\n\t\t\t\t),\n\n\t\t\tsetConfigOption: (request) =>\n\t\t\t\trun(\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst row = yield* found(request.sessionId);\n\t\t\t\t\t\tconst hostDir = Option.getOrUndefined(row.hostDir);\n\t\t\t\t\t\tconst value = String(request.value);\n\t\t\t\t\t\tif (request.configId === Config.MODEL) {\n\t\t\t\t\t\t\tconst model = Option.getOrUndefined(Config.parseModel(value));\n\t\t\t\t\t\t\tif (model === undefined || !(yield* Config.known(model, hostDir))) {\n\t\t\t\t\t\t\t\treturn yield* Agent.RequestError.invalidParams(`Unknown model: ${value}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tyield* Session.attach({ sessionId: row.id, model });\n\t\t\t\t\t\t} else if (request.configId === Config.THOUGHT_LEVEL) {\n\t\t\t\t\t\t\tif (!Config.isThinkingLevel(value)) {\n\t\t\t\t\t\t\t\treturn yield* Agent.RequestError.invalidParams(`Unknown thinking level: ${value}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tyield* Session.attach({ sessionId: row.id, thinkingLevel: value });\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn yield* Agent.RequestError.invalidParams(`Unknown config option: ${request.configId}`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { configOptions: yield* Config.options(yield* Session.configuration(row.id), hostDir) };\n\t\t\t\t\t}),\n\t\t\t\t),\n\n\t\t\tprompt: ({ sessionId: id, prompt }) =>\n\t\t\t\trun(\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst parts = yield* promptParts(prompt);\n\t\t\t\t\t\tconst handle = Option.getOrUndefined(yield* Session.get(sessionId(id)));\n\t\t\t\t\t\tif (handle === undefined) {\n\t\t\t\t\t\t\treturn yield* new SessionStore.SessionNotFoundError({ sessionId: sessionId(id) });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (running.has(id)) {\n\t\t\t\t\t\t\treturn yield* Agent.RequestError.invalidRequest(\"A prompt is already running for this session\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\trunning.add(id);\n\t\t\t\t\t\tyield* Effect.addFinalizer(() => Effect.sync(() => running.delete(id)));\n\n\t\t\t\t\t\t// Forward this execution's updates until it settles; the settling event decides the answer.\n\t\t\t\t\t\tlet reason: EventList.LLMEnded[\"data\"][\"reason\"] | undefined;\n\t\t\t\t\t\t// Plugins are checked every exchange; tell the user about each failure once per prompt.\n\t\t\t\t\t\tconst notices = new Set<string>();\n\t\t\t\t\t\tconst settled = yield* handle.events().pipe(\n\t\t\t\t\t\t\tStream.tap((event) => {\n\t\t\t\t\t\t\t\tif (isLLMEnded(event)) reason = event.data.reason;\n\t\t\t\t\t\t\t\tlet update = Feed.update(event);\n\t\t\t\t\t\t\t\tconst notice = Feed.notice(event);\n\t\t\t\t\t\t\t\tif (Option.isSome(notice) && !notices.has(notice.value)) {\n\t\t\t\t\t\t\t\t\tnotices.add(notice.value);\n\t\t\t\t\t\t\t\t\tupdate = Option.some(Feed.noticeUpdate(notice.value));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn Option.match(update, {\n\t\t\t\t\t\t\t\t\tonNone: () => Effect.void,\n\t\t\t\t\t\t\t\t\tonSome: (update) => client.sessionUpdate({ sessionId: id, update }).pipe(Effect.ignore),\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tStream.filter(isSettled),\n\t\t\t\t\t\t\tStream.runHead,\n\t\t\t\t\t\t\tEffect.forkScoped({ startImmediately: true }),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst before = (yield* handle.info).title;\n\t\t\t\t\t\tyield* handle.run({ parts });\n\t\t\t\t\t\tconst end = yield* Fiber.join(settled);\n\n\t\t\t\t\t\t// The harness titles a session from its first prompt; tell the editor.\n\t\t\t\t\t\tconst { title } = yield* handle.info;\n\t\t\t\t\t\tif (title !== before) {\n\t\t\t\t\t\t\tyield* client\n\t\t\t\t\t\t\t\t.sessionUpdate({ sessionId: id, update: { sessionUpdate: \"session_info_update\", title } })\n\t\t\t\t\t\t\t\t.pipe(Effect.ignore);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (Option.isNone(end) || isInterrupted(end.value)) return { stopReason: \"cancelled\" as const };\n\t\t\t\t\t\tif (isFailed(end.value)) return yield* Agent.RequestError.internalError(end.value.data.error.message);\n\t\t\t\t\t\treturn { stopReason: reason === \"length\" ? (\"max_tokens\" as const) : (\"end_turn\" as const) };\n\t\t\t\t\t}).pipe(Effect.scoped),\n\t\t\t\t),\n\n\t\t\tcancel: ({ sessionId: id }) => control.interrupt(sessionId(id), { reason: \"user\" }).pipe(Effect.asVoid),\n\t\t};\n\t};\n});\n\nexport * as Handlers from \"./handlers.ts\";\n","import { Control, Harness, Sandbox } from \"@codeworksh/harness/effect\";\nimport { Effect, Logger, Stdio } from \"effect\";\nimport { Agent } from \"./agent.ts\";\nimport { Handlers } from \"./handlers.ts\";\n\n// Sessions and managed sandboxes outlive any single request; the connection's end is what stops them.\nconst shutdown = Effect.gen(function* () {\n\tconst control = yield* Control.Service;\n\tyield* Effect.forEach(\n\t\tyield* control.active,\n\t\t(id) =>\n\t\t\tcontrol\n\t\t\t\t.interrupt(id, { reason: \"shutdown\", awaitSettlement: true })\n\t\t\t\t.pipe(Effect.timeout(\"10 seconds\"), Effect.ignore),\n\t\t{ concurrency: \"unbounded\", discard: true },\n\t);\n\tconst managed = (yield* Sandbox.list()).filter((info) => info.ownership === \"managed\");\n\tyield* Effect.forEach(\n\t\tmanaged,\n\t\t(info) =>\n\t\t\tSandbox.stop(info.id).pipe(\n\t\t\t\tEffect.timeout(\"10 seconds\"),\n\t\t\t\tEffect.catchCause((cause) =>\n\t\t\t\t\tEffect.logError(\"Failed to stop managed sandbox during ACP shutdown\", cause).pipe(\n\t\t\t\t\t\tEffect.annotateLogs({ sandboxInstanceId: info.id }),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t{ concurrency: \"unbounded\", discard: true },\n\t);\n});\n\n/**\n * Serves ACP v1 on stdio until the client disconnects.\n *\n * stdout carries the protocol, so logs go to stderr. The reference is set outside the harness layer\n * so the fibers it forks (turns, plugin loads) inherit it too.\n */\nexport const serve = (options: Harness.Options) =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.addFinalizer(() => shutdown.pipe(Effect.ignore));\n\t\tconst handlers = yield* Handlers.make;\n\t\tyield* Agent.serve(yield* Stdio.Stdio, handlers);\n\t}).pipe(Effect.scoped, Effect.provide(Harness.layer(options)), Effect.provideService(Logger.LogToStderr, true));\n\nexport * as Server from \"./server.ts\";\n","import { Effect } from \"effect\";\nimport { Server } from \"../../../acp/server.ts\";\nimport { Runtime } from \"../../../framework/runtime.ts\";\nimport { reportFailure } from \"../../error.ts\";\nimport { harnessOptions } from \"../../harness.ts\";\nimport { Cmd } from \"../cmd.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.acp,\n\tEffect.fn(\"CLI.acp\")(function* () {\n\t\tconst shared = yield* Cmd.spec;\n\t\treturn yield* Server.serve(harnessOptions(shared)).pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":"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"}