@codeworksh/cli 0.0.1-dev.20260925163815 → 0.1.0-canary.16.1.gfa1c6c4c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/acp-DK_xXx9y.mjs +494 -0
- package/acp-DK_xXx9y.mjs.map +1 -0
- package/{add-BPuCxrRi.mjs → add-B9gIgFb3.mjs} +4 -4
- package/{add-BPuCxrRi.mjs.map → add-B9gIgFb3.mjs.map} +1 -1
- package/{catalog-DyQXd30n.mjs → catalog-D5BxyTfH.mjs} +2 -2
- package/{catalog-DyQXd30n.mjs.map → catalog-D5BxyTfH.mjs.map} +1 -1
- package/{check-CKi11Mtm.mjs → check-B9PJ6rn_.mjs} +4 -4
- package/{check-CKi11Mtm.mjs.map → check-B9PJ6rn_.mjs.map} +1 -1
- package/{entries-BXBULTVt.mjs → entries-CzgqHfKQ.mjs} +3 -3
- package/{entries-BXBULTVt.mjs.map → entries-CzgqHfKQ.mjs.map} +1 -1
- package/{error-CxoEKg-4.mjs → error-C9ACQhhu.mjs} +2 -2
- package/error-C9ACQhhu.mjs.map +1 -0
- package/index.mjs +20 -21
- package/index.mjs.map +1 -1
- package/{install-C2QXwvU6.mjs → install-Cw6h6IRB.mjs} +4 -4
- package/{install-C2QXwvU6.mjs.map → install-Cw6h6IRB.mjs.map} +1 -1
- package/{link-D5uOUo0m.mjs → link-B7iVolAn.mjs} +3 -3
- package/{link-D5uOUo0m.mjs.map → link-B7iVolAn.mjs.map} +1 -1
- package/{list-B7wmE2Hz.mjs → list-3hYMW1Wo.mjs} +4 -4
- package/{list-B7wmE2Hz.mjs.map → list-3hYMW1Wo.mjs.map} +1 -1
- package/{list-CEDVgkex.mjs → list-BAonMfru.mjs} +4 -4
- package/{list-CEDVgkex.mjs.map → list-BAonMfru.mjs.map} +1 -1
- package/{login-DD5n0PHg.mjs → login-CXelgTth.mjs} +4 -4
- package/{login-DD5n0PHg.mjs.map → login-CXelgTth.mjs.map} +1 -1
- package/{logout--lzv9ftF.mjs → logout-DrQQPxEW.mjs} +4 -4
- package/{logout--lzv9ftF.mjs.map → logout-DrQQPxEW.mjs.map} +1 -1
- package/package-7FOUqcPO.mjs +6 -0
- package/package-7FOUqcPO.mjs.map +1 -0
- package/package.json +8 -6
- package/{providers-CO0ERtiv.mjs → providers-DksUoT4Z.mjs} +4 -4
- package/{providers-CO0ERtiv.mjs.map → providers-DksUoT4Z.mjs.map} +1 -1
- package/{refresh-DKBOk5RX.mjs → refresh-CHBg5ya9.mjs} +4 -4
- package/{refresh-DKBOk5RX.mjs.map → refresh-CHBg5ya9.mjs.map} +1 -1
- package/{refresh-BcI6iAiQ.mjs → refresh-DPBpboO0.mjs} +4 -4
- package/{refresh-BcI6iAiQ.mjs.map → refresh-DPBpboO0.mjs.map} +1 -1
- package/{reload-L4NyTZaU.mjs → reload-DDsh7kFG.mjs} +3 -3
- package/{reload-L4NyTZaU.mjs.map → reload-DDsh7kFG.mjs.map} +1 -1
- package/{remove-CpLi76Ah.mjs → remove-__JfeHO-.mjs} +4 -4
- package/{remove-CpLi76Ah.mjs.map → remove-__JfeHO-.mjs.map} +1 -1
- package/{run-D7h83L_m.mjs → run-D47jXr5Q.mjs} +3 -5
- package/run-D47jXr5Q.mjs.map +1 -0
- package/{runtime-B3dlWGfs.mjs → runtime-D4zyJPrh.mjs} +9 -2
- package/runtime-D4zyJPrh.mjs.map +1 -0
- package/{serve-BGrH_Wr6.mjs → serve-gOODO9pv.mjs} +14 -10
- package/{serve-BGrH_Wr6.mjs.map → serve-gOODO9pv.mjs.map} +1 -1
- package/{settings-aqM_b9UE.mjs → settings-DDkmAxW5.mjs} +2 -2
- package/{settings-aqM_b9UE.mjs.map → settings-DDkmAxW5.mjs.map} +1 -1
- package/{shared-IycfDUnF.mjs → shared-DFB2--6V.mjs} +4 -4
- package/{shared-IycfDUnF.mjs.map → shared-DFB2--6V.mjs.map} +1 -1
- package/{status-CCj71RVv.mjs → status-BNc5JZ1C.mjs} +4 -4
- package/{status-CCj71RVv.mjs.map → status-BNc5JZ1C.mjs.map} +1 -1
- package/{update-C-RdaEiC.mjs → update-CaW7oDOl.mjs} +4 -4
- package/{update-C-RdaEiC.mjs.map → update-CaW7oDOl.mjs.map} +1 -1
- package/error-CxoEKg-4.mjs.map +0 -1
- package/run-D7h83L_m.mjs.map +0 -1
- package/runtime-B3dlWGfs.mjs.map +0 -1
package/acp-DK_xXx9y.mjs
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
import { t as version } from "./package-7FOUqcPO.mjs";
|
|
2
|
+
import { i as Cmd, t as handler } from "./runtime-D4zyJPrh.mjs";
|
|
3
|
+
import { i as reportFailure } from "./error-C9ACQhhu.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-DK_xXx9y.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acp-DK_xXx9y.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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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as Cmd, t as handler } from "./runtime-
|
|
2
|
-
import { d as writeOut, i as reportFailure } from "./error-
|
|
3
|
-
import { a as resolveTarget, c as withPluginsLock, i as readPlugins, l as writePlugins, n as matches, o as spellings, t as identify, u as written } from "./settings-
|
|
1
|
+
import { i as Cmd, t as handler } from "./runtime-D4zyJPrh.mjs";
|
|
2
|
+
import { d as writeOut, i as reportFailure } from "./error-C9ACQhhu.mjs";
|
|
3
|
+
import { a as resolveTarget, c as withPluginsLock, i as readPlugins, l as writePlugins, n as matches, o as spellings, t as identify, u as written } from "./settings-DDkmAxW5.mjs";
|
|
4
4
|
import { Effect, Layer, Option, Path } from "effect";
|
|
5
5
|
import { Database, Event, Global, Plugin, Session, SessionStore } from "@codeworksh/harness/effect";
|
|
6
6
|
//#region src/cli/cmd/handlers/plugin/session.ts
|
|
@@ -79,4 +79,4 @@ var add_default = handler(Cmd.commands.plugin.commands.add, Effect.fn("CLI.plugi
|
|
|
79
79
|
//#endregion
|
|
80
80
|
export { add_default as default };
|
|
81
81
|
|
|
82
|
-
//# sourceMappingURL=add-
|
|
82
|
+
//# sourceMappingURL=add-B9gIgFb3.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-BPuCxrRi.mjs","names":["Runtime.handler"],"sources":["../../src/cli/cmd/handlers/plugin/session.ts","../../src/cli/cmd/handlers/plugin/add.ts"],"sourcesContent":["import { Database, Event, Global, Session, SessionStore } from \"@codeworksh/harness/effect\";\nimport { Effect, Layer, Option } from \"effect\";\n\n/**\n * The host directory a session is linked to.\n *\n * **A session ID can answer this and a project ID cannot**, which is why the flag takes one. A\n * `Project` is env-independent by design -- its identity is a repo marker, a remote hash or a root\n * commit, never a path -- and its spaces hold `location`s *inside* an env, which may be a container\n * on another machine. Deriving a host settings file from one would mean walking the host\n * filesystem from a path that means something somewhere else, which is the exact failure the\n * `hostDir` split exists to prevent: it does not error, it finds a stranger's project.\n *\n * A session, by contrast, carries a `hostDir` that was *declared* on the host. Absent is a normal\n * state rather than corruption, and it is the one this refuses.\n */\nexport const linkedDirectory = Effect.fn(\"CLI.plugin.linkedDirectory\")(function* (\n\tsessionId: string,\n\thome: Option.Option<string>,\n) {\n\tconst paths = yield* Global.resolve(Option.isNone(home) ? {} : { home: home.value });\n\tconst id = Session.SessionSchema.ID.ascending(sessionId);\n\n\treturn yield* Effect.gen(function* () {\n\t\tconst sessions = yield* SessionStore.Service;\n\t\tconst found = yield* sessions.get(id);\n\t\tif (Option.isNone(found)) return yield* new SessionStore.SessionNotFoundError({ sessionId: id });\n\t\tconst hostDir = Option.getOrUndefined(found.value.hostDir);\n\t\tif (hostDir === undefined) return yield* new SessionStore.SessionNotLinkedError({ sessionId: id });\n\t\treturn hostDir;\n\t}).pipe(\n\t\t// Only the session row is read, so this needs the database and the event log the store is\n\t\t// built on -- no sandboxes, no control plane, no plugin machinery.\n\t\tEffect.provide(\n\t\t\tSessionStore.layer.pipe(\n\t\t\t\tLayer.provide(Event.layer),\n\t\t\t\tLayer.provide(Database.layer(yield* Database.path(paths.data))),\n\t\t\t),\n\t\t),\n\t);\n});\n","import { Global, Plugin } from \"@codeworksh/harness/effect\";\nimport { Effect, Option, Path } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport { linkedDirectory } from \"./session.ts\";\nimport {\n\tidentify,\n\tmatches,\n\treadPlugins,\n\tresolveTarget,\n\tspellings,\n\twithPluginsLock,\n\twritePlugins,\n\twritten,\n} from \"./settings.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.plugin.commands.add,\n\tEffect.fn(\"CLI.plugin.add\")(function* ({ package: reference, global: userWide, session }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst shared = yield* Cmd.spec;\n\t\t\tconst path = yield* Path.Path;\n\t\t\tconst paths = yield* Global.resolve(Option.isNone(shared.home) ? {} : { home: shared.home.value });\n\n\t\t\t// A session names the project to write into when the shell's directory is not it --\n\t\t\t// a server or a UI acting on a session's behalf, rather than a person standing in the\n\t\t\t// repository. It fails when that session has no project, which is a state `session\n\t\t\t// link` exists to fix.\n\t\t\tconst linked = Option.isNone(session) ? undefined : yield* linkedDirectory(session.value, shared.home);\n\t\t\t/*\n\t\t\t * One directory answers every question this command asks about the reference, and it\n\t\t\t * is resolved before any of them.\n\t\t\t *\n\t\t\t * A relative spec anchors here, the `.npmrc` chain governing the install is read from\n\t\t\t * here, and the entry is written anchored here. Splitting them is not a cosmetic\n\t\t\t * inconsistency: under `--session` the shell's directory is a server's, so validating\n\t\t\t * `./plugins/x.ts` against it imports one file and writes a reference to another, and\n\t\t\t * reading the `.npmrc` chain from it installs from the wrong registry -- a private\n\t\t\t * scope's token lives in the project being written to, not wherever the server runs.\n\t\t\t */\n\t\t\tconst from = linked ?? path.resolve(\".\");\n\n\t\t\t// The file the entry will land in decides the install's registry identity: it is named\n\t\t\t// here -- without creating the marker -- so the store keys the artifact under the same\n\t\t\t// `.npmrc` chain every later resolve of this entry re-derives, and a bad reference\n\t\t\t// still leaves nothing behind.\n\t\t\tconst target = yield* resolveTarget(shared, userWide, linked, false);\n\n\t\t\t// Install and import before touching the file: a spec that turns out not to be a plugin\n\t\t\t// should fail here, with its own error, rather than at the next run from a file the user\n\t\t\t// then has to repair by hand.\n\t\t\tconst plugin = yield* Plugin.inspect(reference, { cache: paths.cache, hostDir: from, file: target.path });\n\t\t\t// What goes in the file, which is not always what was typed: a relative path anchors to\n\t\t\t// the settings file being written, not to the directory the command ran in.\n\t\t\tconst entry = yield* written(reference, {\n\t\t\t\thostDir: from,\n\t\t\t\tfile: target.path,\n\t\t\t\troot: target.root,\n\t\t\t});\n\t\t\tconst spelled = yield* spellings(reference, from);\n\t\t\tconst version = plugin.version === undefined ? \"\" : `@${plugin.version}`;\n\t\t\tyield* withPluginsLock(\n\t\t\t\ttarget.path,\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst { source, plugins } = yield* readPlugins(target.path);\n\t\t\t\t\tconst entries = yield* identify(plugins, target.path, paths.cache);\n\t\t\t\t\t// Configured already if any spelling of an existing entry names this plugin -- the same\n\t\t\t\t\t// package under a different version, the path it was added by, or the ID it declares.\n\t\t\t\t\tconst names = (candidate: (typeof entries)[number]) =>\n\t\t\t\t\t\tmatches(candidate, spelled) || candidate.answers.has(plugin.id);\n\t\t\t\t\tconst existing = entries.findIndex((candidate) => candidate.loads && names(candidate));\n\t\t\t\t\tif (existing >= 0) {\n\t\t\t\t\t\tconst current = entries[existing]?.value;\n\t\t\t\t\t\tif (current === entry) {\n\t\t\t\t\t\t\tyield* writeOut(`Plugin \"${reference}\" is already configured in ${target.path}\\n`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst replaced = [...plugins];\n\t\t\t\t\t\treplaced[existing] = entry;\n\t\t\t\t\t\tyield* writePlugins(target.path, source, replaced);\n\t\t\t\t\t\tyield* writeOut(\n\t\t\t\t\t\t\t`Updated ${plugin.id} (${String(current)} -> ${entry}${version}) in ${target.path}\\n`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Put the loader before existing configuration so its options apply to the module.\n\t\t\t\t\tconst configured = entries.findIndex((candidate) => !candidate.loads && names(candidate));\n\t\t\t\t\tconst updated = [...plugins];\n\t\t\t\t\tupdated.splice(configured < 0 ? updated.length : configured, 0, entry);\n\t\t\t\t\tyield* writePlugins(target.path, source, updated);\n\t\t\t\t\tyield* writeOut(`Added ${plugin.id} (${entry}${version}) to ${target.path}\\n`);\n\t\t\t\t}),\n\t\t\t);\n\t\t\t// Said after the write, because `resolveTarget` only named the marker: the lock's\n\t\t\t// write is what made it, and \"created\" should be true by the time it is printed.\n\t\t\tif (target.created !== undefined) yield* writeOut(`Created ${target.created}/\\n`);\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"add-B9gIgFb3.mjs","names":["Runtime.handler"],"sources":["../../src/cli/cmd/handlers/plugin/session.ts","../../src/cli/cmd/handlers/plugin/add.ts"],"sourcesContent":["import { Database, Event, Global, Session, SessionStore } from \"@codeworksh/harness/effect\";\nimport { Effect, Layer, Option } from \"effect\";\n\n/**\n * The host directory a session is linked to.\n *\n * **A session ID can answer this and a project ID cannot**, which is why the flag takes one. A\n * `Project` is env-independent by design -- its identity is a repo marker, a remote hash or a root\n * commit, never a path -- and its spaces hold `location`s *inside* an env, which may be a container\n * on another machine. Deriving a host settings file from one would mean walking the host\n * filesystem from a path that means something somewhere else, which is the exact failure the\n * `hostDir` split exists to prevent: it does not error, it finds a stranger's project.\n *\n * A session, by contrast, carries a `hostDir` that was *declared* on the host. Absent is a normal\n * state rather than corruption, and it is the one this refuses.\n */\nexport const linkedDirectory = Effect.fn(\"CLI.plugin.linkedDirectory\")(function* (\n\tsessionId: string,\n\thome: Option.Option<string>,\n) {\n\tconst paths = yield* Global.resolve(Option.isNone(home) ? {} : { home: home.value });\n\tconst id = Session.SessionSchema.ID.ascending(sessionId);\n\n\treturn yield* Effect.gen(function* () {\n\t\tconst sessions = yield* SessionStore.Service;\n\t\tconst found = yield* sessions.get(id);\n\t\tif (Option.isNone(found)) return yield* new SessionStore.SessionNotFoundError({ sessionId: id });\n\t\tconst hostDir = Option.getOrUndefined(found.value.hostDir);\n\t\tif (hostDir === undefined) return yield* new SessionStore.SessionNotLinkedError({ sessionId: id });\n\t\treturn hostDir;\n\t}).pipe(\n\t\t// Only the session row is read, so this needs the database and the event log the store is\n\t\t// built on -- no sandboxes, no control plane, no plugin machinery.\n\t\tEffect.provide(\n\t\t\tSessionStore.layer.pipe(\n\t\t\t\tLayer.provide(Event.layer),\n\t\t\t\tLayer.provide(Database.layer(yield* Database.path(paths.data))),\n\t\t\t),\n\t\t),\n\t);\n});\n","import { Global, Plugin } from \"@codeworksh/harness/effect\";\nimport { Effect, Option, Path } from \"effect\";\nimport { Runtime } from \"../../../../framework/runtime.ts\";\nimport { reportFailure } from \"../../../error.ts\";\nimport { writeOut } from \"../../../output.ts\";\nimport { Cmd } from \"../../cmd.ts\";\nimport { linkedDirectory } from \"./session.ts\";\nimport {\n\tidentify,\n\tmatches,\n\treadPlugins,\n\tresolveTarget,\n\tspellings,\n\twithPluginsLock,\n\twritePlugins,\n\twritten,\n} from \"./settings.ts\";\n\nexport default Runtime.handler(\n\tCmd.commands.plugin.commands.add,\n\tEffect.fn(\"CLI.plugin.add\")(function* ({ package: reference, global: userWide, session }) {\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst shared = yield* Cmd.spec;\n\t\t\tconst path = yield* Path.Path;\n\t\t\tconst paths = yield* Global.resolve(Option.isNone(shared.home) ? {} : { home: shared.home.value });\n\n\t\t\t// A session names the project to write into when the shell's directory is not it --\n\t\t\t// a server or a UI acting on a session's behalf, rather than a person standing in the\n\t\t\t// repository. It fails when that session has no project, which is a state `session\n\t\t\t// link` exists to fix.\n\t\t\tconst linked = Option.isNone(session) ? undefined : yield* linkedDirectory(session.value, shared.home);\n\t\t\t/*\n\t\t\t * One directory answers every question this command asks about the reference, and it\n\t\t\t * is resolved before any of them.\n\t\t\t *\n\t\t\t * A relative spec anchors here, the `.npmrc` chain governing the install is read from\n\t\t\t * here, and the entry is written anchored here. Splitting them is not a cosmetic\n\t\t\t * inconsistency: under `--session` the shell's directory is a server's, so validating\n\t\t\t * `./plugins/x.ts` against it imports one file and writes a reference to another, and\n\t\t\t * reading the `.npmrc` chain from it installs from the wrong registry -- a private\n\t\t\t * scope's token lives in the project being written to, not wherever the server runs.\n\t\t\t */\n\t\t\tconst from = linked ?? path.resolve(\".\");\n\n\t\t\t// The file the entry will land in decides the install's registry identity: it is named\n\t\t\t// here -- without creating the marker -- so the store keys the artifact under the same\n\t\t\t// `.npmrc` chain every later resolve of this entry re-derives, and a bad reference\n\t\t\t// still leaves nothing behind.\n\t\t\tconst target = yield* resolveTarget(shared, userWide, linked, false);\n\n\t\t\t// Install and import before touching the file: a spec that turns out not to be a plugin\n\t\t\t// should fail here, with its own error, rather than at the next run from a file the user\n\t\t\t// then has to repair by hand.\n\t\t\tconst plugin = yield* Plugin.inspect(reference, { cache: paths.cache, hostDir: from, file: target.path });\n\t\t\t// What goes in the file, which is not always what was typed: a relative path anchors to\n\t\t\t// the settings file being written, not to the directory the command ran in.\n\t\t\tconst entry = yield* written(reference, {\n\t\t\t\thostDir: from,\n\t\t\t\tfile: target.path,\n\t\t\t\troot: target.root,\n\t\t\t});\n\t\t\tconst spelled = yield* spellings(reference, from);\n\t\t\tconst version = plugin.version === undefined ? \"\" : `@${plugin.version}`;\n\t\t\tyield* withPluginsLock(\n\t\t\t\ttarget.path,\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst { source, plugins } = yield* readPlugins(target.path);\n\t\t\t\t\tconst entries = yield* identify(plugins, target.path, paths.cache);\n\t\t\t\t\t// Configured already if any spelling of an existing entry names this plugin -- the same\n\t\t\t\t\t// package under a different version, the path it was added by, or the ID it declares.\n\t\t\t\t\tconst names = (candidate: (typeof entries)[number]) =>\n\t\t\t\t\t\tmatches(candidate, spelled) || candidate.answers.has(plugin.id);\n\t\t\t\t\tconst existing = entries.findIndex((candidate) => candidate.loads && names(candidate));\n\t\t\t\t\tif (existing >= 0) {\n\t\t\t\t\t\tconst current = entries[existing]?.value;\n\t\t\t\t\t\tif (current === entry) {\n\t\t\t\t\t\t\tyield* writeOut(`Plugin \"${reference}\" is already configured in ${target.path}\\n`);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst replaced = [...plugins];\n\t\t\t\t\t\treplaced[existing] = entry;\n\t\t\t\t\t\tyield* writePlugins(target.path, source, replaced);\n\t\t\t\t\t\tyield* writeOut(\n\t\t\t\t\t\t\t`Updated ${plugin.id} (${String(current)} -> ${entry}${version}) in ${target.path}\\n`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Put the loader before existing configuration so its options apply to the module.\n\t\t\t\t\tconst configured = entries.findIndex((candidate) => !candidate.loads && names(candidate));\n\t\t\t\t\tconst updated = [...plugins];\n\t\t\t\t\tupdated.splice(configured < 0 ? updated.length : configured, 0, entry);\n\t\t\t\t\tyield* writePlugins(target.path, source, updated);\n\t\t\t\t\tyield* writeOut(`Added ${plugin.id} (${entry}${version}) to ${target.path}\\n`);\n\t\t\t\t}),\n\t\t\t);\n\t\t\t// Said after the write, because `resolveTarget` only named the marker: the lock's\n\t\t\t// write is what made it, and \"created\" should be true by the time it is printed.\n\t\t\tif (target.created !== undefined) yield* writeOut(`Created ${target.created}/\\n`);\n\t\t});\n\n\t\treturn yield* program.pipe(Effect.catch(reportFailure));\n\t}),\n);\n"],"mappings":"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"}
|