@codeworksh/harness 0.0.1-dev.20260824182323 → 0.0.1-dev.20260824191503
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/README.md +15 -0
- package/cli/index.mjs +78 -8
- package/cli/index.mjs.map +1 -1
- package/effect.mjs +1 -1
- package/package.json +1 -1
- package/{session-CF1B0VEr.mjs → session-DZZfASHn.mjs} +29 -20
- package/session-DZZfASHn.mjs.map +1 -0
- package/session-CF1B0VEr.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -76,6 +76,21 @@ pnpm dlx @codeworksh/harness@dev \
|
|
|
76
76
|
"Inspect this repository"
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
+
The streamed response remains clean on stdout for piping. Session context and the per-run model usage summary are written to stderr:
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
session ses_...
|
|
83
|
+
sandbox local · /workspace/project
|
|
84
|
+
|
|
85
|
+
── response ─────────────────────────────────────────────────────────────
|
|
86
|
+
The response streams here.
|
|
87
|
+
── usage ────────────────────────────────────────────────────────────────
|
|
88
|
+
model openai/gpt-5.5
|
|
89
|
+
tokens 12,400 input · 820 output · 13,220 total
|
|
90
|
+
cache 9,600 read · 0 write
|
|
91
|
+
cost $0.014200 · 1 turn
|
|
92
|
+
```
|
|
93
|
+
|
|
79
94
|
`modelgen [path]` uses Aikit's model generator and writes `./models.gen.json` by default. Set `CODEWORK_MODELS_FILE` or pass a path when you keep the catalog elsewhere.
|
|
80
95
|
|
|
81
96
|
The CLI prints the session ID to stderr. Provider, model, and thinking settings are stored with the session, so use the same home directory and session ID to continue it:
|
package/cli/index.mjs
CHANGED
|
@@ -1,10 +1,49 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as create, d as
|
|
3
|
-
import { Effect, Fiber, Option, Queue, Schema, Stream } from "effect";
|
|
2
|
+
import { a as create, d as LLMEnded, f as LLMTextDelta, i as Drivers, l as layer, m as ID, n as create$1, o as register, p as TurnEnded, t as attach } from "../session-DZZfASHn.mjs";
|
|
3
|
+
import { Effect, Fiber, Option, Queue, Ref, Schema, Stream } from "effect";
|
|
4
4
|
import { generateModels } from "@codeworksh/aikit/modelgen";
|
|
5
5
|
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
6
6
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
7
7
|
import { Argument, Command, Flag } from "effect/unstable/cli";
|
|
8
|
+
//#region src/cli/output.ts
|
|
9
|
+
const emptyUsage = {
|
|
10
|
+
turns: 0,
|
|
11
|
+
input: 0,
|
|
12
|
+
output: 0,
|
|
13
|
+
reasoning: 0,
|
|
14
|
+
cacheRead: 0,
|
|
15
|
+
cacheWrite: 0,
|
|
16
|
+
totalTokens: 0,
|
|
17
|
+
cost: 0
|
|
18
|
+
};
|
|
19
|
+
const addUsage = (summary, message) => ({
|
|
20
|
+
turns: summary.turns + 1,
|
|
21
|
+
provider: message.provider.id,
|
|
22
|
+
model: message.responseModel ?? message.model,
|
|
23
|
+
input: summary.input + message.usage.input,
|
|
24
|
+
output: summary.output + message.usage.output,
|
|
25
|
+
reasoning: summary.reasoning + (message.usage.reasoning ?? 0),
|
|
26
|
+
cacheRead: summary.cacheRead + message.usage.cacheRead,
|
|
27
|
+
cacheWrite: summary.cacheWrite + message.usage.cacheWrite,
|
|
28
|
+
totalTokens: summary.totalTokens + message.usage.totalTokens,
|
|
29
|
+
cost: summary.cost + message.usage.cost.total
|
|
30
|
+
});
|
|
31
|
+
const number = new Intl.NumberFormat("en-US");
|
|
32
|
+
const row = (label, value) => `${label.padEnd(9)}${value}\n`;
|
|
33
|
+
const formatCost = (cost) => `$${cost.toFixed(cost > 0 && cost < .01 ? 6 : 4)}`;
|
|
34
|
+
const divider = (label, columns = 72) => {
|
|
35
|
+
const width = Math.min(100, Math.max(32, columns));
|
|
36
|
+
const start = `── ${label} `;
|
|
37
|
+
return `${start}${"─".repeat(Math.max(2, width - start.length))}\n`;
|
|
38
|
+
};
|
|
39
|
+
const header = (input) => `${row("session", input.sessionId)}${row("sandbox", `${input.sandbox} · ${input.directory}`)}\n${divider("response", input.columns)}`;
|
|
40
|
+
const usage = (summary, columns) => {
|
|
41
|
+
const turns = `${summary.turns} ${summary.turns === 1 ? "turn" : "turns"}`;
|
|
42
|
+
const model = summary.provider === void 0 || summary.model === void 0 ? "unknown" : `${summary.provider}/${summary.model}`;
|
|
43
|
+
const reasoning = summary.reasoning === 0 ? "" : ` · ${number.format(summary.reasoning)} reasoning`;
|
|
44
|
+
return `${divider("usage", columns)}${row("model", model)}${row("tokens", `${number.format(summary.input)} input · ${number.format(summary.output)} output${reasoning} · ${number.format(summary.totalTokens)} total`)}${row("cache", `${number.format(summary.cacheRead)} read · ${number.format(summary.cacheWrite)} write`)}${row("cost", `${formatCost(summary.cost)} · ${turns}`)}`;
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
8
47
|
//#region src/cli/index.ts
|
|
9
48
|
const thinkingLevels = [
|
|
10
49
|
"off",
|
|
@@ -22,14 +61,35 @@ const sandboxDrivers = [
|
|
|
22
61
|
];
|
|
23
62
|
const writeOut = (value) => Effect.sync(() => void process.stdout.write(value));
|
|
24
63
|
const writeError = (value) => Effect.sync(() => void process.stderr.write(value));
|
|
64
|
+
const terminalColumns = () => process.stderr.isTTY ? process.stderr.columns ?? 72 : 72;
|
|
25
65
|
var InvalidInputError = class extends Schema.TaggedError()("CLI.InvalidInputError", { message: Schema.String }) {};
|
|
26
66
|
var ModelgenError = class extends Schema.TaggedError()("CLI.ModelgenError", { cause: Schema.Defect() }) {};
|
|
27
|
-
const
|
|
28
|
-
|
|
67
|
+
const initialRenderState = {
|
|
68
|
+
usage: emptyUsage,
|
|
69
|
+
textSeen: false,
|
|
70
|
+
textEndsWithNewline: false
|
|
71
|
+
};
|
|
72
|
+
const isTextDelta = Schema.is(LLMTextDelta);
|
|
73
|
+
const isLLMEnded = Schema.is(LLMEnded);
|
|
74
|
+
const isTurnEnded = Schema.is(TurnEnded);
|
|
75
|
+
const render = (ended, state) => Effect.fn("CLI.render")(function* (event) {
|
|
76
|
+
if (isTextDelta(event)) {
|
|
29
77
|
yield* writeOut(event.data.delta);
|
|
78
|
+
if (event.data.delta.length > 0) yield* Ref.update(state, (current) => ({
|
|
79
|
+
...current,
|
|
80
|
+
textSeen: true,
|
|
81
|
+
textEndsWithNewline: event.data.delta.endsWith("\n")
|
|
82
|
+
}));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (isLLMEnded(event)) {
|
|
86
|
+
yield* Ref.update(state, (current) => ({
|
|
87
|
+
...current,
|
|
88
|
+
usage: addUsage(current.usage, event.data.message)
|
|
89
|
+
}));
|
|
30
90
|
return;
|
|
31
91
|
}
|
|
32
|
-
if (event
|
|
92
|
+
if (isTurnEnded(event)) yield* Queue.offer(ended, event.data.messageId);
|
|
33
93
|
});
|
|
34
94
|
const awaitMessage = Effect.fn("CLI.awaitMessage")(function* (ended, messageId) {
|
|
35
95
|
while ((yield* Queue.take(ended)) !== messageId);
|
|
@@ -87,13 +147,23 @@ const run = Command.make("run", {
|
|
|
87
147
|
});
|
|
88
148
|
}
|
|
89
149
|
const ended = yield* Queue.unbounded();
|
|
90
|
-
const
|
|
91
|
-
yield*
|
|
150
|
+
const renderState = yield* Ref.make(initialRenderState);
|
|
151
|
+
const printer = yield* handle.events().pipe(Stream.runForEach(render(ended, renderState)), Effect.forkScoped({ startImmediately: true }));
|
|
152
|
+
const info = yield* handle.info;
|
|
153
|
+
const columns = terminalColumns();
|
|
154
|
+
yield* writeError(header({
|
|
155
|
+
sessionId: handle.id,
|
|
156
|
+
sandbox: info.sandbox?.driver ?? "local",
|
|
157
|
+
directory: info.directory,
|
|
158
|
+
columns
|
|
159
|
+
}));
|
|
92
160
|
yield* handle.run(prompt);
|
|
93
161
|
const leaf = (yield* handle.path()).at(-1);
|
|
94
162
|
if (leaf !== void 0) yield* awaitMessage(ended, leaf.entry.id);
|
|
95
163
|
yield* Fiber.interrupt(printer);
|
|
96
|
-
yield*
|
|
164
|
+
const rendered = yield* Ref.get(renderState);
|
|
165
|
+
if (rendered.textSeen && !rendered.textEndsWithNewline) yield* writeOut("\n");
|
|
166
|
+
yield* writeError(usage(rendered.usage, columns));
|
|
97
167
|
}).pipe(Effect.provide(layer({
|
|
98
168
|
...Option.isNone(shared.home) ? {} : { home: shared.home.value },
|
|
99
169
|
...Option.isNone(shared.database) ? {} : { database: shared.database.value },
|
package/cli/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["Sandbox.create","Sandbox.register","Session.attach","Session.create","Harness.layer"],"sources":["../../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { generateModels } from \"@codeworksh/aikit/modelgen\";\nimport * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport * as NodeServices from \"@effect/platform-node/NodeServices\";\nimport { Effect, Fiber, Option, Queue, Schema, Stream } from \"effect\";\nimport { Argument, CliError, Command, Flag } from \"effect/unstable/cli\";\nimport { Harness } from \"../effect/harness.ts\";\nimport { Sandbox } from \"../effect/sandbox.ts\";\nimport { Session } from \"../effect/session.ts\";\nimport type { EventSchema } from \"../event/schema.ts\";\n\nconst thinkingLevels = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nconst sandboxDrivers = [\"local\", \"daytona\", \"vercel\"] as const;\n\nconst writeOut = (value: string) => Effect.sync(() => void process.stdout.write(value));\nconst writeError = (value: string) => Effect.sync(() => void process.stderr.write(value));\n\nclass InvalidInputError extends Schema.TaggedError<InvalidInputError>()(\"CLI.InvalidInputError\", {\n\tmessage: Schema.String,\n}) {}\n\nclass ModelgenError extends Schema.TaggedError<ModelgenError>()(\"CLI.ModelgenError\", {\n\tcause: Schema.Defect(),\n}) {}\n\nconst render = (ended: Queue.Queue<string>) =>\n\tEffect.fn(\"CLI.render\")(function* (event: EventSchema.Payload) {\n\t\tif (event.type === \"session.llm.text.delta\") {\n\t\t\tyield* writeOut((event.data as { readonly delta: string }).delta);\n\t\t\treturn;\n\t\t}\n\t\tif (event.type === \"session.turn.ended\") {\n\t\t\tyield* Queue.offer(ended, (event.data as { readonly messageId: string }).messageId);\n\t\t}\n\t});\n\nconst awaitMessage = Effect.fn(\"CLI.awaitMessage\")(function* (ended: Queue.Queue<string>, messageId: string) {\n\twhile ((yield* Queue.take(ended)) !== messageId) {\n\t\t// Earlier turns in the same drain are expected when a tool call continues.\n\t}\n});\n\nconst selectSandbox = Effect.fn(\"CLI.selectSandbox\")(function* (\n\tdriver: (typeof sandboxDrivers)[number],\n\tproviderResourceId?: string,\n) {\n\tif (driver === \"local\") return undefined;\n\tif (driver === \"daytona\") {\n\t\treturn providerResourceId === undefined\n\t\t\t? yield* Sandbox.create({ driver })\n\t\t\t: yield* Sandbox.register({ driver, providerResourceId });\n\t}\n\treturn providerResourceId === undefined\n\t\t? yield* Sandbox.create({ driver })\n\t\t: yield* Sandbox.register({ driver, providerResourceId });\n});\n\nconst root = Command.make(\"codework\").pipe(\n\tCommand.withSharedFlags({\n\t\thome: Flag.string(\"home\").pipe(Flag.withDescription(\"Harness data directory\"), Flag.optional),\n\t\tdatabase: Flag.string(\"database\").pipe(Flag.withDescription(\"SQLite path or :memory:\"), Flag.optional),\n\t}),\n\tCommand.withDescription(\"Run Codework agent sessions\"),\n);\n\nconst run = Command.make(\n\t\"run\",\n\t{\n\t\tprompt: Argument.string(\"prompt\").pipe(Argument.withDescription(\"Prompt for the agent\")),\n\t\tsession: Flag.string(\"session\").pipe(\n\t\t\tFlag.withAlias(\"s\"),\n\t\t\tFlag.withDescription(\"Continue an existing session ID\"),\n\t\t\tFlag.optional,\n\t\t),\n\t\tcwd: Flag.string(\"cwd\").pipe(\n\t\t\tFlag.withAlias(\"C\"),\n\t\t\tFlag.withDescription(\"Working directory for a new session\"),\n\t\t\tFlag.optional,\n\t\t),\n\t\tsandbox: Flag.choice(\"sandbox\", sandboxDrivers).pipe(\n\t\t\tFlag.withDescription(\"Sandbox for a new session (default: local)\"),\n\t\t\tFlag.optional,\n\t\t),\n\t\tsandboxProviderId: Flag.string(\"sandbox-provider-id\").pipe(\n\t\t\tFlag.withDescription(\"Provider ID of an existing sandbox\"),\n\t\t\tFlag.optional,\n\t\t),\n\t\tprovider: Flag.string(\"provider\").pipe(Flag.withDescription(\"Model catalog provider ID\"), Flag.optional),\n\t\tmodel: Flag.string(\"model\").pipe(Flag.withDescription(\"Model ID\"), Flag.optional),\n\t\tthinking: Flag.choice(\"thinking\", thinkingLevels).pipe(Flag.withDescription(\"Thinking level\"), Flag.optional),\n\t},\n\tEffect.fn(\"CLI.run\")(function* ({ prompt, session, cwd, sandbox, sandboxProviderId, provider, model, thinking }) {\n\t\tconst shared = yield* root;\n\t\tif (\n\t\t\tOption.isSome(session) &&\n\t\t\t(Option.isSome(cwd) || Option.isSome(sandbox) || Option.isSome(sandboxProviderId))\n\t\t) {\n\t\t\treturn yield* new InvalidInputError({\n\t\t\t\tmessage: \"--cwd, --sandbox, and --sandbox-provider-id can only be used when creating a new session\",\n\t\t\t});\n\t\t}\n\t\tif (Option.isSome(provider) !== Option.isSome(model)) {\n\t\t\treturn yield* new InvalidInputError({ message: \"--provider and --model must be provided together\" });\n\t\t}\n\t\tif (Option.isSome(sandboxProviderId) && (Option.isNone(sandbox) || sandbox.value === \"local\")) {\n\t\t\treturn yield* new InvalidInputError({ message: \"--sandbox-provider-id requires a remote --sandbox\" });\n\t\t}\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst runtime = {\n\t\t\t\t...(Option.isNone(provider) || Option.isNone(model)\n\t\t\t\t\t? {}\n\t\t\t\t\t: { model: { provider: provider.value, id: model.value } }),\n\t\t\t\t...(Option.isNone(thinking) ? {} : { thinkingLevel: thinking.value }),\n\t\t\t};\n\t\t\tlet handle: Session.Handle;\n\t\t\tif (Option.isSome(session)) {\n\t\t\t\thandle = yield* Session.attach({ sessionId: Session.SessionSchema.ID.make(session.value), ...runtime });\n\t\t\t} else {\n\t\t\t\tconst selectedSandbox = Option.getOrElse(sandbox, () => \"local\" as const);\n\t\t\t\tconst selected = yield* selectSandbox(selectedSandbox, Option.getOrUndefined(sandboxProviderId));\n\t\t\t\thandle = yield* Session.create({\n\t\t\t\t\ttitle: \"CLI\",\n\t\t\t\t\t...runtime,\n\t\t\t\t\t...(selected === undefined ? {} : { sandbox: selected }),\n\t\t\t\t\t...(Option.isNone(cwd) ? {} : { directory: cwd.value }),\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst ended = yield* Queue.unbounded<string>();\n\t\t\tconst printer = yield* handle\n\t\t\t\t.events()\n\t\t\t\t.pipe(Stream.runForEach(render(ended)), Effect.forkScoped({ startImmediately: true }));\n\n\t\t\tyield* writeError(`session ${handle.id}\\n`);\n\t\t\tyield* handle.run(prompt);\n\t\t\tconst path = yield* handle.path();\n\t\t\tconst leaf = path.at(-1);\n\t\t\tif (leaf !== undefined) yield* awaitMessage(ended, leaf.entry.id);\n\t\t\tyield* Fiber.interrupt(printer);\n\t\t\tyield* writeOut(\"\\n\");\n\t\t});\n\n\t\treturn yield* program.pipe(\n\t\t\tEffect.provide(\n\t\t\t\tHarness.layer({\n\t\t\t\t\t...(Option.isNone(shared.home) ? {} : { home: shared.home.value }),\n\t\t\t\t\t...(Option.isNone(shared.database) ? {} : { database: shared.database.value }),\n\t\t\t\t\tsandboxes: [Sandbox.Drivers.daytona(), Sandbox.Drivers.vercel()],\n\t\t\t\t}),\n\t\t\t),\n\t\t\tEffect.scoped,\n\t\t);\n\t}),\n).pipe(\n\tCommand.withDescription(\"Start or continue an agent session\"),\n\tCommand.withExamples([\n\t\t{ command: 'codework run \"Inspect the failing tests\"', description: \"Create a session\" },\n\t\t{\n\t\t\tcommand: 'codework run --provider openai --model gpt-5.5 --thinking high \"Inspect the failing tests\"',\n\t\t\tdescription: \"Create a session with an explicit model\",\n\t\t},\n\t\t{\n\t\t\tcommand: 'codework run --sandbox daytona \"Inspect the repository\"',\n\t\t\tdescription: \"Create a Daytona sandbox and session\",\n\t\t},\n\t\t{\n\t\t\tcommand: 'codework run --sandbox daytona --sandbox-provider-id <id> \"Inspect the repository\"',\n\t\t\tdescription: \"Use an existing remote sandbox\",\n\t\t},\n\t\t{\n\t\t\tcommand: 'codework run --session <id> --provider openai --model gpt-5.6-luna \"Now fix them\"',\n\t\t\tdescription: \"Continue a session with explicit model bindings\",\n\t\t},\n\t]),\n);\n\nconst modelgen = Command.make(\n\t\"modelgen\",\n\t{\n\t\tpath: Argument.string(\"path\").pipe(\n\t\t\tArgument.withDescription(\"Output path; defaults to CODEWORK_MODELS_FILE or ./models.gen.json\"),\n\t\t\tArgument.optional,\n\t\t),\n\t},\n\tEffect.fn(\"CLI.modelgen\")(function* ({ path }) {\n\t\tconst generated = yield* Effect.tryPromise({\n\t\t\ttry: () => generateModels(Option.isNone(path) ? {} : { path: path.value }),\n\t\t\tcatch: (cause) => new ModelgenError({ cause }),\n\t\t});\n\t\tyield* writeOut(`Generated model catalog at ${generated}\\n`);\n\t}),\n).pipe(\n\tCommand.withDescription(\"Generate the Aikit model catalog\"),\n\tCommand.withExamples([{ command: \"codework modelgen\", description: \"Generate models.gen.json\" }]),\n);\n\nexport const command = root.pipe(Command.withSubcommands([run, modelgen]));\n\nexport const main: Effect.Effect<void, Command.Error<typeof command> | CliError.CliError> = Command.run(command, {\n\tversion: \"0.0.1\",\n}).pipe(Effect.provide(NodeServices.layer));\n\nNodeRuntime.runMain(main);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["EventList.LLMTextDelta","EventList.LLMEnded","EventList.TurnEnded","Sandbox.create","Sandbox.register","Session.attach","Session.create","Harness.layer"],"sources":["../../../src/cli/output.ts","../../../src/cli/index.ts"],"sourcesContent":["import type { Message } from \"@codeworksh/aikit\";\n\nexport interface UsageSummary {\n\treadonly turns: number;\n\treadonly provider?: string;\n\treadonly model?: string;\n\treadonly input: number;\n\treadonly output: number;\n\treadonly reasoning: number;\n\treadonly cacheRead: number;\n\treadonly cacheWrite: number;\n\treadonly totalTokens: number;\n\treadonly cost: number;\n}\n\nexport const emptyUsage: UsageSummary = {\n\tturns: 0,\n\tinput: 0,\n\toutput: 0,\n\treasoning: 0,\n\tcacheRead: 0,\n\tcacheWrite: 0,\n\ttotalTokens: 0,\n\tcost: 0,\n};\n\nexport const addUsage = (summary: UsageSummary, message: Message.AssistantMessage): UsageSummary => ({\n\tturns: summary.turns + 1,\n\tprovider: message.provider.id,\n\tmodel: message.responseModel ?? message.model,\n\tinput: summary.input + message.usage.input,\n\toutput: summary.output + message.usage.output,\n\treasoning: summary.reasoning + (message.usage.reasoning ?? 0),\n\tcacheRead: summary.cacheRead + message.usage.cacheRead,\n\tcacheWrite: summary.cacheWrite + message.usage.cacheWrite,\n\ttotalTokens: summary.totalTokens + message.usage.totalTokens,\n\tcost: summary.cost + message.usage.cost.total,\n});\n\nconst number = new Intl.NumberFormat(\"en-US\");\nconst row = (label: string, value: string) => `${label.padEnd(9)}${value}\\n`;\n\nconst formatCost = (cost: number): string => `$${cost.toFixed(cost > 0 && cost < 0.01 ? 6 : 4)}`;\n\nexport const divider = (label: string, columns = 72): string => {\n\tconst width = Math.min(100, Math.max(32, columns));\n\tconst start = `── ${label} `;\n\treturn `${start}${\"─\".repeat(Math.max(2, width - start.length))}\\n`;\n};\n\nexport const header = (input: {\n\treadonly sessionId: string;\n\treadonly sandbox: string;\n\treadonly directory: string;\n\treadonly columns?: number;\n}): string =>\n\t`${row(\"session\", input.sessionId)}${row(\"sandbox\", `${input.sandbox} · ${input.directory}`)}\\n${divider(\n\t\t\"response\",\n\t\tinput.columns,\n\t)}`;\n\nexport const usage = (summary: UsageSummary, columns?: number): string => {\n\tconst turns = `${summary.turns} ${summary.turns === 1 ? \"turn\" : \"turns\"}`;\n\tconst model =\n\t\tsummary.provider === undefined || summary.model === undefined\n\t\t\t? \"unknown\"\n\t\t\t: `${summary.provider}/${summary.model}`;\n\tconst reasoning = summary.reasoning === 0 ? \"\" : ` · ${number.format(summary.reasoning)} reasoning`;\n\treturn `${divider(\"usage\", columns)}${row(\"model\", model)}${row(\n\t\t\"tokens\",\n\t\t`${number.format(summary.input)} input · ${number.format(summary.output)} output${reasoning} · ${number.format(\n\t\t\tsummary.totalTokens,\n\t\t)} total`,\n\t)}${row(\"cache\", `${number.format(summary.cacheRead)} read · ${number.format(summary.cacheWrite)} write`)}${row(\n\t\t\"cost\",\n\t\t`${formatCost(summary.cost)} · ${turns}`,\n\t)}`;\n};\n","#!/usr/bin/env node\n\nimport { generateModels } from \"@codeworksh/aikit/modelgen\";\nimport * as NodeRuntime from \"@effect/platform-node/NodeRuntime\";\nimport * as NodeServices from \"@effect/platform-node/NodeServices\";\nimport { Effect, Fiber, Option, Queue, Ref, Schema, Stream } from \"effect\";\nimport { Argument, CliError, Command, Flag } from \"effect/unstable/cli\";\nimport { Harness } from \"../effect/harness.ts\";\nimport { Sandbox } from \"../effect/sandbox.ts\";\nimport { Session } from \"../effect/session.ts\";\nimport { EventList } from \"../event/list.ts\";\nimport type { EventSchema } from \"../event/schema.ts\";\nimport { addUsage, emptyUsage, header, usage, type UsageSummary } from \"./output.ts\";\n\nconst thinkingLevels = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\", \"max\"] as const;\nconst sandboxDrivers = [\"local\", \"daytona\", \"vercel\"] as const;\n\nconst writeOut = (value: string) => Effect.sync(() => void process.stdout.write(value));\nconst writeError = (value: string) => Effect.sync(() => void process.stderr.write(value));\nconst terminalColumns = () => (process.stderr.isTTY ? (process.stderr.columns ?? 72) : 72);\n\nclass InvalidInputError extends Schema.TaggedError<InvalidInputError>()(\"CLI.InvalidInputError\", {\n\tmessage: Schema.String,\n}) {}\n\nclass ModelgenError extends Schema.TaggedError<ModelgenError>()(\"CLI.ModelgenError\", {\n\tcause: Schema.Defect(),\n}) {}\n\ninterface RenderState {\n\treadonly usage: UsageSummary;\n\treadonly textSeen: boolean;\n\treadonly textEndsWithNewline: boolean;\n}\n\nconst initialRenderState: RenderState = {\n\tusage: emptyUsage,\n\ttextSeen: false,\n\ttextEndsWithNewline: false,\n};\n\nconst isTextDelta = Schema.is(EventList.LLMTextDelta);\nconst isLLMEnded = Schema.is(EventList.LLMEnded);\nconst isTurnEnded = Schema.is(EventList.TurnEnded);\n\nconst render = (ended: Queue.Queue<string>, state: Ref.Ref<RenderState>) =>\n\tEffect.fn(\"CLI.render\")(function* (event: EventSchema.Payload) {\n\t\tif (isTextDelta(event)) {\n\t\t\tyield* writeOut(event.data.delta);\n\t\t\tif (event.data.delta.length > 0) {\n\t\t\t\tyield* Ref.update(state, (current) => ({\n\t\t\t\t\t...current,\n\t\t\t\t\ttextSeen: true,\n\t\t\t\t\ttextEndsWithNewline: event.data.delta.endsWith(\"\\n\"),\n\t\t\t\t}));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (isLLMEnded(event)) {\n\t\t\tyield* Ref.update(state, (current) => ({ ...current, usage: addUsage(current.usage, event.data.message) }));\n\t\t\treturn;\n\t\t}\n\t\tif (isTurnEnded(event)) {\n\t\t\tyield* Queue.offer(ended, event.data.messageId);\n\t\t}\n\t});\n\nconst awaitMessage = Effect.fn(\"CLI.awaitMessage\")(function* (ended: Queue.Queue<string>, messageId: string) {\n\twhile ((yield* Queue.take(ended)) !== messageId) {\n\t\t// Earlier turns in the same drain are expected when a tool call continues.\n\t}\n});\n\nconst selectSandbox = Effect.fn(\"CLI.selectSandbox\")(function* (\n\tdriver: (typeof sandboxDrivers)[number],\n\tproviderResourceId?: string,\n) {\n\tif (driver === \"local\") return undefined;\n\tif (driver === \"daytona\") {\n\t\treturn providerResourceId === undefined\n\t\t\t? yield* Sandbox.create({ driver })\n\t\t\t: yield* Sandbox.register({ driver, providerResourceId });\n\t}\n\treturn providerResourceId === undefined\n\t\t? yield* Sandbox.create({ driver })\n\t\t: yield* Sandbox.register({ driver, providerResourceId });\n});\n\nconst root = Command.make(\"codework\").pipe(\n\tCommand.withSharedFlags({\n\t\thome: Flag.string(\"home\").pipe(Flag.withDescription(\"Harness data directory\"), Flag.optional),\n\t\tdatabase: Flag.string(\"database\").pipe(Flag.withDescription(\"SQLite path or :memory:\"), Flag.optional),\n\t}),\n\tCommand.withDescription(\"Run Codework agent sessions\"),\n);\n\nconst run = Command.make(\n\t\"run\",\n\t{\n\t\tprompt: Argument.string(\"prompt\").pipe(Argument.withDescription(\"Prompt for the agent\")),\n\t\tsession: Flag.string(\"session\").pipe(\n\t\t\tFlag.withAlias(\"s\"),\n\t\t\tFlag.withDescription(\"Continue an existing session ID\"),\n\t\t\tFlag.optional,\n\t\t),\n\t\tcwd: Flag.string(\"cwd\").pipe(\n\t\t\tFlag.withAlias(\"C\"),\n\t\t\tFlag.withDescription(\"Working directory for a new session\"),\n\t\t\tFlag.optional,\n\t\t),\n\t\tsandbox: Flag.choice(\"sandbox\", sandboxDrivers).pipe(\n\t\t\tFlag.withDescription(\"Sandbox for a new session (default: local)\"),\n\t\t\tFlag.optional,\n\t\t),\n\t\tsandboxProviderId: Flag.string(\"sandbox-provider-id\").pipe(\n\t\t\tFlag.withDescription(\"Provider ID of an existing sandbox\"),\n\t\t\tFlag.optional,\n\t\t),\n\t\tprovider: Flag.string(\"provider\").pipe(Flag.withDescription(\"Model catalog provider ID\"), Flag.optional),\n\t\tmodel: Flag.string(\"model\").pipe(Flag.withDescription(\"Model ID\"), Flag.optional),\n\t\tthinking: Flag.choice(\"thinking\", thinkingLevels).pipe(Flag.withDescription(\"Thinking level\"), Flag.optional),\n\t},\n\tEffect.fn(\"CLI.run\")(function* ({ prompt, session, cwd, sandbox, sandboxProviderId, provider, model, thinking }) {\n\t\tconst shared = yield* root;\n\t\tif (\n\t\t\tOption.isSome(session) &&\n\t\t\t(Option.isSome(cwd) || Option.isSome(sandbox) || Option.isSome(sandboxProviderId))\n\t\t) {\n\t\t\treturn yield* new InvalidInputError({\n\t\t\t\tmessage: \"--cwd, --sandbox, and --sandbox-provider-id can only be used when creating a new session\",\n\t\t\t});\n\t\t}\n\t\tif (Option.isSome(provider) !== Option.isSome(model)) {\n\t\t\treturn yield* new InvalidInputError({ message: \"--provider and --model must be provided together\" });\n\t\t}\n\t\tif (Option.isSome(sandboxProviderId) && (Option.isNone(sandbox) || sandbox.value === \"local\")) {\n\t\t\treturn yield* new InvalidInputError({ message: \"--sandbox-provider-id requires a remote --sandbox\" });\n\t\t}\n\t\tconst program = Effect.gen(function* () {\n\t\t\tconst runtime = {\n\t\t\t\t...(Option.isNone(provider) || Option.isNone(model)\n\t\t\t\t\t? {}\n\t\t\t\t\t: { model: { provider: provider.value, id: model.value } }),\n\t\t\t\t...(Option.isNone(thinking) ? {} : { thinkingLevel: thinking.value }),\n\t\t\t};\n\t\t\tlet handle: Session.Handle;\n\t\t\tif (Option.isSome(session)) {\n\t\t\t\thandle = yield* Session.attach({ sessionId: Session.SessionSchema.ID.make(session.value), ...runtime });\n\t\t\t} else {\n\t\t\t\tconst selectedSandbox = Option.getOrElse(sandbox, () => \"local\" as const);\n\t\t\t\tconst selected = yield* selectSandbox(selectedSandbox, Option.getOrUndefined(sandboxProviderId));\n\t\t\t\thandle = yield* Session.create({\n\t\t\t\t\ttitle: \"CLI\",\n\t\t\t\t\t...runtime,\n\t\t\t\t\t...(selected === undefined ? {} : { sandbox: selected }),\n\t\t\t\t\t...(Option.isNone(cwd) ? {} : { directory: cwd.value }),\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst ended = yield* Queue.unbounded<string>();\n\t\t\tconst renderState = yield* Ref.make(initialRenderState);\n\t\t\tconst printer = yield* handle\n\t\t\t\t.events()\n\t\t\t\t.pipe(Stream.runForEach(render(ended, renderState)), Effect.forkScoped({ startImmediately: true }));\n\n\t\t\tconst info = yield* handle.info;\n\t\t\tconst columns = terminalColumns();\n\t\t\tyield* writeError(\n\t\t\t\theader({\n\t\t\t\t\tsessionId: handle.id,\n\t\t\t\t\tsandbox: info.sandbox?.driver ?? \"local\",\n\t\t\t\t\tdirectory: info.directory,\n\t\t\t\t\tcolumns,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tyield* handle.run(prompt);\n\t\t\tconst path = yield* handle.path();\n\t\t\tconst leaf = path.at(-1);\n\t\t\tif (leaf !== undefined) yield* awaitMessage(ended, leaf.entry.id);\n\t\t\tyield* Fiber.interrupt(printer);\n\t\t\tconst rendered = yield* Ref.get(renderState);\n\t\t\tif (rendered.textSeen && !rendered.textEndsWithNewline) yield* writeOut(\"\\n\");\n\t\t\tyield* writeError(usage(rendered.usage, columns));\n\t\t});\n\n\t\treturn yield* program.pipe(\n\t\t\tEffect.provide(\n\t\t\t\tHarness.layer({\n\t\t\t\t\t...(Option.isNone(shared.home) ? {} : { home: shared.home.value }),\n\t\t\t\t\t...(Option.isNone(shared.database) ? {} : { database: shared.database.value }),\n\t\t\t\t\tsandboxes: [Sandbox.Drivers.daytona(), Sandbox.Drivers.vercel()],\n\t\t\t\t}),\n\t\t\t),\n\t\t\tEffect.scoped,\n\t\t);\n\t}),\n).pipe(\n\tCommand.withDescription(\"Start or continue an agent session\"),\n\tCommand.withExamples([\n\t\t{ command: 'codework run \"Inspect the failing tests\"', description: \"Create a session\" },\n\t\t{\n\t\t\tcommand: 'codework run --provider openai --model gpt-5.5 --thinking high \"Inspect the failing tests\"',\n\t\t\tdescription: \"Create a session with an explicit model\",\n\t\t},\n\t\t{\n\t\t\tcommand: 'codework run --sandbox daytona \"Inspect the repository\"',\n\t\t\tdescription: \"Create a Daytona sandbox and session\",\n\t\t},\n\t\t{\n\t\t\tcommand: 'codework run --sandbox daytona --sandbox-provider-id <id> \"Inspect the repository\"',\n\t\t\tdescription: \"Use an existing remote sandbox\",\n\t\t},\n\t\t{\n\t\t\tcommand: 'codework run --session <id> --provider openai --model gpt-5.6-luna \"Now fix them\"',\n\t\t\tdescription: \"Continue a session with explicit model bindings\",\n\t\t},\n\t]),\n);\n\nconst modelgen = Command.make(\n\t\"modelgen\",\n\t{\n\t\tpath: Argument.string(\"path\").pipe(\n\t\t\tArgument.withDescription(\"Output path; defaults to CODEWORK_MODELS_FILE or ./models.gen.json\"),\n\t\t\tArgument.optional,\n\t\t),\n\t},\n\tEffect.fn(\"CLI.modelgen\")(function* ({ path }) {\n\t\tconst generated = yield* Effect.tryPromise({\n\t\t\ttry: () => generateModels(Option.isNone(path) ? {} : { path: path.value }),\n\t\t\tcatch: (cause) => new ModelgenError({ cause }),\n\t\t});\n\t\tyield* writeOut(`Generated model catalog at ${generated}\\n`);\n\t}),\n).pipe(\n\tCommand.withDescription(\"Generate the Aikit model catalog\"),\n\tCommand.withExamples([{ command: \"codework modelgen\", description: \"Generate models.gen.json\" }]),\n);\n\nexport const command = root.pipe(Command.withSubcommands([run, modelgen]));\n\nexport const main: Effect.Effect<void, Command.Error<typeof command> | CliError.CliError> = Command.run(command, {\n\tversion: \"0.0.1\",\n}).pipe(Effect.provide(NodeServices.layer));\n\nNodeRuntime.runMain(main);\n"],"mappings":"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"}
|
package/effect.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __exportAll } from "./rolldown-runtime-B4iAMlE-.mjs";
|
|
2
|
-
import { c as harness_exports, r as session_exports, s as sandbox_exports, u as tool_exports } from "./session-
|
|
2
|
+
import { c as harness_exports, r as session_exports, s as sandbox_exports, u as tool_exports } from "./session-DZZfASHn.mjs";
|
|
3
3
|
//#region src/effect/tools.ts
|
|
4
4
|
var tools_exports = /* @__PURE__ */ __exportAll({
|
|
5
5
|
Tools: () => tools_exports,
|
package/package.json
CHANGED
|
@@ -985,7 +985,6 @@ const layer$20 = Layer.effect(Service$13, Effect.gen(function* () {
|
|
|
985
985
|
const sql = yield* SqlClient.SqlClient;
|
|
986
986
|
const pubsub = {
|
|
987
987
|
all: yield* PubSub.unbounded(),
|
|
988
|
-
durable: /* @__PURE__ */ new Map(),
|
|
989
988
|
typed: /* @__PURE__ */ new Map()
|
|
990
989
|
};
|
|
991
990
|
const projectors = /* @__PURE__ */ new Map();
|
|
@@ -993,7 +992,6 @@ const layer$20 = Layer.effect(Service$13, Effect.gen(function* () {
|
|
|
993
992
|
yield* Effect.addFinalizer(() => Effect.gen(function* () {
|
|
994
993
|
yield* PubSub.shutdown(pubsub.all);
|
|
995
994
|
yield* Effect.forEach(pubsub.typed.values(), PubSub.shutdown, { discard: true });
|
|
996
|
-
yield* Effect.forEach(pubsub.durable.values(), (wakes) => Effect.forEach(wakes, PubSub.shutdown, { discard: true }), { discard: true });
|
|
997
995
|
}));
|
|
998
996
|
const observe = (event, observer) => Effect.suspend(() => observer(event)).pipe(Effect.catchCauseIf((cause) => !Cause.hasInterrupts(cause), (cause) => Effect.logError("Event listener failed", {
|
|
999
997
|
eventID: event.id,
|
|
@@ -1097,7 +1095,7 @@ const layer$20 = Layer.effect(Service$13, Effect.gen(function* () {
|
|
|
1097
1095
|
message: `Expected string aggregate field ${durable.aggregate}`
|
|
1098
1096
|
}));
|
|
1099
1097
|
const encoded = yield* Schema.encodeUnknownEffect(definition.data)(event.data);
|
|
1100
|
-
|
|
1098
|
+
return yield* sql.withTransaction(Effect.gen(function* () {
|
|
1101
1099
|
const { seq } = yield* bumpSequence(aggregateId);
|
|
1102
1100
|
const existing = yield* findEventById(event.id);
|
|
1103
1101
|
if (Option.isSome(existing)) return yield* Effect.die(new InvalidDurableEventError({
|
|
@@ -1122,8 +1120,6 @@ const layer$20 = Layer.effect(Service$13, Effect.gen(function* () {
|
|
|
1122
1120
|
});
|
|
1123
1121
|
return payload;
|
|
1124
1122
|
}));
|
|
1125
|
-
yield* Effect.forEach(pubsub.durable.get(aggregateId) ?? [], (wake) => PubSub.publish(wake, void 0), { discard: true });
|
|
1126
|
-
return committed;
|
|
1127
1123
|
}, Effect.orDie, Effect.uninterruptible);
|
|
1128
1124
|
const publishEvent = Effect.fn("Event.publishEvent")(function* (definition, event) {
|
|
1129
1125
|
if (definition.durable) {
|
|
@@ -1175,19 +1171,32 @@ const layer$20 = Layer.effect(Service$13, Effect.gen(function* () {
|
|
|
1175
1171
|
const subscribe = (definition) => Stream.unwrap(getOrCreate(definition).pipe(Effect.map((created) => Stream.fromPubSub(created)))).pipe(Stream.map((event) => event));
|
|
1176
1172
|
const streamAll = () => Stream.fromPubSub(pubsub.all);
|
|
1177
1173
|
const stream = (input) => {
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1174
|
+
const forSession = (event) => event.data.sessionId === input.sessionId;
|
|
1175
|
+
const after = input.after;
|
|
1176
|
+
if (after === void 0) return streamAll().pipe(Stream.filter(forSession));
|
|
1177
|
+
return Stream.unwrap(Effect.gen(function* () {
|
|
1178
|
+
const subscription = yield* PubSub.subscribe(pubsub.all);
|
|
1179
|
+
const watermark = yield* Ref.make(after);
|
|
1180
|
+
const history = Stream.paginate(after, Effect.fn("Event.stream.history")(function* (after) {
|
|
1181
|
+
const page = yield* readAggregate({
|
|
1182
|
+
aggregateId: input.sessionId,
|
|
1183
|
+
after,
|
|
1184
|
+
limit: 100,
|
|
1185
|
+
manifest: Manifest
|
|
1186
|
+
});
|
|
1187
|
+
const last = page.events.at(-1);
|
|
1188
|
+
const next = page.hasMore && last?.durable !== void 0 ? Option.some(last.durable.seq) : Option.none();
|
|
1189
|
+
return [page.events, next];
|
|
1190
|
+
})).pipe(Stream.map((event) => event), Stream.tap((event) => {
|
|
1191
|
+
const seq = event.durable?.seq;
|
|
1192
|
+
return seq === void 0 ? Effect.void : Ref.update(watermark, (current) => Math.max(current, seq));
|
|
1193
|
+
}));
|
|
1194
|
+
const tail = Stream.fromSubscription(subscription).pipe(Stream.filter(forSession), Stream.filterEffect((event) => {
|
|
1195
|
+
const seq = event.durable?.seq;
|
|
1196
|
+
return seq === void 0 ? Effect.succeed(true) : Ref.get(watermark).pipe(Effect.map((replayed) => seq > replayed));
|
|
1197
|
+
}));
|
|
1198
|
+
return history.pipe(Stream.concat(tail));
|
|
1199
|
+
}));
|
|
1191
1200
|
};
|
|
1192
1201
|
const listen = (listener) => Effect.sync(() => {
|
|
1193
1202
|
listeners.push(listener);
|
|
@@ -7265,6 +7274,6 @@ const attach = Effect.fn("Session.attach")(function* (input) {
|
|
|
7265
7274
|
return found.value;
|
|
7266
7275
|
});
|
|
7267
7276
|
//#endregion
|
|
7268
|
-
export { create$2 as a, harness_exports as c,
|
|
7277
|
+
export { create$2 as a, harness_exports as c, LLMEnded as d, LLMTextDelta as f, Drivers as i, layer as l, ID$4 as m, create$1 as n, register as o, TurnEnded as p, session_exports as r, sandbox_exports as s, attach as t, tool_exports as u };
|
|
7269
7278
|
|
|
7270
|
-
//# sourceMappingURL=session-
|
|
7279
|
+
//# sourceMappingURL=session-DZZfASHn.mjs.map
|