ferix-code 0.0.2-beta.3 → 0.0.2-beta.5
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/dist/index.d.ts +475 -14
- package/dist/index.js +1455 -773
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -71,10 +71,11 @@ import { Command } from "commander";
|
|
|
71
71
|
// package.json
|
|
72
72
|
var package_default = {
|
|
73
73
|
name: "ferix-code",
|
|
74
|
-
version: "0.0.2-beta.
|
|
74
|
+
version: "0.0.2-beta.5",
|
|
75
75
|
description: "Composable RALPH loops for AI coding agents - v2 with Effect",
|
|
76
76
|
type: "module",
|
|
77
77
|
bin: {
|
|
78
|
+
ferix: "dist/index.js",
|
|
78
79
|
"ferix-code": "dist/index.js"
|
|
79
80
|
},
|
|
80
81
|
files: [
|
|
@@ -116,7 +117,7 @@ var package_default = {
|
|
|
116
117
|
|
|
117
118
|
// src/program.ts
|
|
118
119
|
init_esm_shims();
|
|
119
|
-
import { Effect as
|
|
120
|
+
import { Effect as Effect21, Stream as Stream10 } from "effect";
|
|
120
121
|
|
|
121
122
|
// src/consumers/index.ts
|
|
122
123
|
init_esm_shims();
|
|
@@ -1303,6 +1304,34 @@ stateReducerRegistry.register(loopStartedReducer);
|
|
|
1303
1304
|
stateReducerRegistry.register(loopCompletedReducer);
|
|
1304
1305
|
stateReducerRegistry.register(loopFailedReducer);
|
|
1305
1306
|
|
|
1307
|
+
// src/consumers/tui/reducers/progress.ts
|
|
1308
|
+
init_esm_shims();
|
|
1309
|
+
var learningRecordedReducer = {
|
|
1310
|
+
tag: "LearningRecorded",
|
|
1311
|
+
reduce: (state, event) => {
|
|
1312
|
+
const category = event.category ? `[${event.category}] ` : "";
|
|
1313
|
+
const line = `Learning: ${category}${event.content}`;
|
|
1314
|
+
return appendOutput(state, `${line}
|
|
1315
|
+
`);
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
var guardrailAddedReducer = {
|
|
1319
|
+
tag: "GuardrailAdded",
|
|
1320
|
+
reduce: (state, event) => {
|
|
1321
|
+
const severityIcon = event.severity === "critical" ? "[critical]" : "[warn]";
|
|
1322
|
+
const line = `${severityIcon} Guardrail: ${event.pattern}`;
|
|
1323
|
+
return appendOutput(state, `${line}
|
|
1324
|
+
`);
|
|
1325
|
+
}
|
|
1326
|
+
};
|
|
1327
|
+
var progressUpdatedReducer = {
|
|
1328
|
+
tag: "ProgressUpdated",
|
|
1329
|
+
reduce: (state) => state
|
|
1330
|
+
};
|
|
1331
|
+
stateReducerRegistry.register(learningRecordedReducer);
|
|
1332
|
+
stateReducerRegistry.register(guardrailAddedReducer);
|
|
1333
|
+
stateReducerRegistry.register(progressUpdatedReducer);
|
|
1334
|
+
|
|
1306
1335
|
// src/consumers/tui/reducers/tasks.ts
|
|
1307
1336
|
init_esm_shims();
|
|
1308
1337
|
var tasksDefinedReducer = {
|
|
@@ -2305,23 +2334,13 @@ ${errorText}
|
|
|
2305
2334
|
|
|
2306
2335
|
// src/layers/index.ts
|
|
2307
2336
|
init_esm_shims();
|
|
2308
|
-
import { Layer as
|
|
2309
|
-
|
|
2310
|
-
// src/layers/llm/claude-cli.ts
|
|
2311
|
-
init_esm_shims();
|
|
2312
|
-
import { spawn } from "child_process";
|
|
2313
|
-
import { Effect as Effect5, Layer, Stream as Stream5 } from "effect";
|
|
2314
|
-
|
|
2315
|
-
// src/services/llm.ts
|
|
2316
|
-
init_esm_shims();
|
|
2317
|
-
import { Context } from "effect";
|
|
2318
|
-
var LLM = class extends Context.Tag("@ferix/LLM")() {
|
|
2319
|
-
};
|
|
2337
|
+
import { Layer as Layer12 } from "effect";
|
|
2320
2338
|
|
|
2321
|
-
// src/layers/
|
|
2339
|
+
// src/layers/guardrails/file-system.ts
|
|
2322
2340
|
init_esm_shims();
|
|
2323
|
-
import {
|
|
2324
|
-
import {
|
|
2341
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
2342
|
+
import { join } from "path";
|
|
2343
|
+
import { DateTime, Effect as Effect4, Layer } from "effect";
|
|
2325
2344
|
|
|
2326
2345
|
// src/domain/errors.ts
|
|
2327
2346
|
init_esm_shims();
|
|
@@ -2334,461 +2353,187 @@ var PlanStoreError = class extends Data.TaggedError("PlanStoreError") {
|
|
|
2334
2353
|
};
|
|
2335
2354
|
var SessionStoreError = class extends Data.TaggedError("SessionStoreError") {
|
|
2336
2355
|
};
|
|
2356
|
+
var ProgressStoreError = class extends Data.TaggedError("ProgressStoreError") {
|
|
2357
|
+
};
|
|
2358
|
+
var GuardrailsStoreError = class extends Data.TaggedError(
|
|
2359
|
+
"GuardrailsStoreError"
|
|
2360
|
+
) {
|
|
2361
|
+
};
|
|
2337
2362
|
var OrchestratorError = class extends Data.TaggedError("OrchestratorError") {
|
|
2338
2363
|
};
|
|
2339
2364
|
|
|
2340
|
-
// src/
|
|
2365
|
+
// src/domain/index.ts
|
|
2341
2366
|
init_esm_shims();
|
|
2342
|
-
function parseJsonLine(line) {
|
|
2343
|
-
if (!line.startsWith("{")) {
|
|
2344
|
-
return null;
|
|
2345
|
-
}
|
|
2346
|
-
try {
|
|
2347
|
-
return JSON.parse(line);
|
|
2348
|
-
} catch {
|
|
2349
|
-
return null;
|
|
2350
|
-
}
|
|
2351
|
-
}
|
|
2352
|
-
function isTextContent(json) {
|
|
2353
|
-
return typeof json === "object" && json !== null && "type" in json && typeof json.type === "string";
|
|
2354
|
-
}
|
|
2355
|
-
function isToolUse(json) {
|
|
2356
|
-
return typeof json === "object" && json !== null && "type" in json && "content_block" in json;
|
|
2357
|
-
}
|
|
2358
|
-
function extractText(json) {
|
|
2359
|
-
if (!isTextContent(json)) {
|
|
2360
|
-
return null;
|
|
2361
|
-
}
|
|
2362
|
-
if (json.type === "content_block_delta") {
|
|
2363
|
-
const delta = json;
|
|
2364
|
-
if (delta.delta?.type === "text_delta" && delta.delta.text) {
|
|
2365
|
-
return delta.delta.text;
|
|
2366
|
-
}
|
|
2367
|
-
}
|
|
2368
|
-
if (json.type === "assistant" && json.message?.content) {
|
|
2369
|
-
for (const block of json.message.content) {
|
|
2370
|
-
if (block.type === "text" && block.text) {
|
|
2371
|
-
return block.text;
|
|
2372
|
-
}
|
|
2373
|
-
}
|
|
2374
|
-
}
|
|
2375
|
-
return null;
|
|
2376
|
-
}
|
|
2377
|
-
function isToolInputDelta(json) {
|
|
2378
|
-
return typeof json === "object" && json !== null && "type" in json && json.type === "content_block_delta" && "delta" in json;
|
|
2379
|
-
}
|
|
2380
|
-
function extractToolInfo(json) {
|
|
2381
|
-
if (typeof json === "object" && json !== null && "type" in json && json.type === "content_block_stop") {
|
|
2382
|
-
return {
|
|
2383
|
-
type: "end",
|
|
2384
|
-
name: "unknown"
|
|
2385
|
-
};
|
|
2386
|
-
}
|
|
2387
|
-
if (!isToolUse(json)) {
|
|
2388
|
-
if (isToolInputDelta(json) && json.delta?.type === "input_json_delta" && json.delta.partial_json) {
|
|
2389
|
-
return {
|
|
2390
|
-
type: "input_delta",
|
|
2391
|
-
name: "",
|
|
2392
|
-
partialJson: json.delta.partial_json
|
|
2393
|
-
};
|
|
2394
|
-
}
|
|
2395
|
-
return null;
|
|
2396
|
-
}
|
|
2397
|
-
if (json.type === "content_block_start" && json.content_block?.type === "tool_use") {
|
|
2398
|
-
return {
|
|
2399
|
-
type: "start",
|
|
2400
|
-
name: json.content_block.name || "unknown"
|
|
2401
|
-
};
|
|
2402
|
-
}
|
|
2403
|
-
return null;
|
|
2404
|
-
}
|
|
2405
|
-
function safeParseJson(jsonStr) {
|
|
2406
|
-
try {
|
|
2407
|
-
return JSON.parse(jsonStr);
|
|
2408
|
-
} catch {
|
|
2409
|
-
return null;
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
function unwrapStreamEvent(json) {
|
|
2413
|
-
if (typeof json === "object" && json !== null && "type" in json && json.type === "stream_event" && "event" in json) {
|
|
2414
|
-
return json.event;
|
|
2415
|
-
}
|
|
2416
|
-
return json;
|
|
2417
|
-
}
|
|
2418
2367
|
|
|
2419
|
-
// src/
|
|
2420
|
-
|
|
2421
|
-
if (toolInfo.type === "start") {
|
|
2422
|
-
toolState.currentTool = toolInfo.name;
|
|
2423
|
-
toolState.inputChunks.length = 0;
|
|
2424
|
-
emit.single({ _tag: "ToolStart", tool: toolInfo.name });
|
|
2425
|
-
return;
|
|
2426
|
-
}
|
|
2427
|
-
if (toolInfo.type === "input_delta" && toolInfo.partialJson) {
|
|
2428
|
-
toolState.inputChunks.push(toolInfo.partialJson);
|
|
2429
|
-
return;
|
|
2430
|
-
}
|
|
2431
|
-
if (toolInfo.type === "end" && toolState.currentTool) {
|
|
2432
|
-
const inputJson = toolState.inputChunks.join("");
|
|
2433
|
-
const input = safeParseJson(inputJson);
|
|
2434
|
-
if (input !== null) {
|
|
2435
|
-
emit.single({ _tag: "ToolUse", tool: toolState.currentTool, input });
|
|
2436
|
-
}
|
|
2437
|
-
emit.single({ _tag: "ToolEnd", tool: toolState.currentTool });
|
|
2438
|
-
toolState.currentTool = "";
|
|
2439
|
-
toolState.inputChunks.length = 0;
|
|
2440
|
-
}
|
|
2441
|
-
}
|
|
2442
|
-
function processJsonLine(json, outputChunks, toolState, emit) {
|
|
2443
|
-
const event = unwrapStreamEvent(json);
|
|
2444
|
-
const text = extractText(event);
|
|
2445
|
-
if (text) {
|
|
2446
|
-
outputChunks.push(text);
|
|
2447
|
-
emit.single({ _tag: "Text", text });
|
|
2448
|
-
return;
|
|
2449
|
-
}
|
|
2450
|
-
const toolInfo = extractToolInfo(event);
|
|
2451
|
-
if (toolInfo) {
|
|
2452
|
-
handleToolEvent(toolInfo, toolState, emit);
|
|
2453
|
-
}
|
|
2454
|
-
}
|
|
2455
|
-
function createEventStream(child) {
|
|
2456
|
-
return Stream4.async((emit) => {
|
|
2457
|
-
const outputChunks = [];
|
|
2458
|
-
const toolState = { currentTool: "", inputChunks: [] };
|
|
2459
|
-
const stdout = child.stdout;
|
|
2460
|
-
if (!stdout) {
|
|
2461
|
-
emit.fail(
|
|
2462
|
-
new LLMError({ message: "Failed to get stdout from child process" })
|
|
2463
|
-
);
|
|
2464
|
-
return Effect4.void;
|
|
2465
|
-
}
|
|
2466
|
-
const rl = createInterface({
|
|
2467
|
-
input: stdout,
|
|
2468
|
-
crlfDelay: Number.POSITIVE_INFINITY
|
|
2469
|
-
});
|
|
2470
|
-
rl.on("line", (line) => {
|
|
2471
|
-
const json = parseJsonLine(line);
|
|
2472
|
-
if (json) {
|
|
2473
|
-
processJsonLine(json, outputChunks, toolState, emit);
|
|
2474
|
-
}
|
|
2475
|
-
});
|
|
2476
|
-
child.stderr?.on("data", (data) => {
|
|
2477
|
-
const text = data.toString().trim();
|
|
2478
|
-
if (text) {
|
|
2479
|
-
emit.single({ _tag: "Text", text: `[stderr] ${text}` });
|
|
2480
|
-
}
|
|
2481
|
-
});
|
|
2482
|
-
child.on("close", (exitCode) => {
|
|
2483
|
-
if (exitCode !== 0) {
|
|
2484
|
-
emit.fail(
|
|
2485
|
-
new LLMError({
|
|
2486
|
-
message: `Claude CLI exited with code ${exitCode}`
|
|
2487
|
-
})
|
|
2488
|
-
);
|
|
2489
|
-
} else {
|
|
2490
|
-
const fullOutput = outputChunks.join("");
|
|
2491
|
-
emit.single({ _tag: "Done", output: fullOutput });
|
|
2492
|
-
emit.end();
|
|
2493
|
-
}
|
|
2494
|
-
});
|
|
2495
|
-
child.on("error", (error) => {
|
|
2496
|
-
emit.fail(
|
|
2497
|
-
new LLMError({
|
|
2498
|
-
message: error.message,
|
|
2499
|
-
cause: error
|
|
2500
|
-
})
|
|
2501
|
-
);
|
|
2502
|
-
});
|
|
2503
|
-
return Effect4.sync(() => {
|
|
2504
|
-
child.kill("SIGTERM");
|
|
2505
|
-
});
|
|
2506
|
-
});
|
|
2507
|
-
}
|
|
2368
|
+
// src/domain/schemas/index.ts
|
|
2369
|
+
init_esm_shims();
|
|
2508
2370
|
|
|
2509
|
-
// src/
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2371
|
+
// src/domain/schemas/config.ts
|
|
2372
|
+
init_esm_shims();
|
|
2373
|
+
import { Schema as S } from "effect";
|
|
2374
|
+
var PhasePromptOverridesSchema = S.Struct({
|
|
2375
|
+
breakdown: S.optional(S.String),
|
|
2376
|
+
planning: S.optional(S.String),
|
|
2377
|
+
execution: S.optional(S.String),
|
|
2378
|
+
check: S.optional(S.String),
|
|
2379
|
+
verify: S.optional(S.String),
|
|
2380
|
+
review: S.optional(S.String),
|
|
2381
|
+
completion: S.optional(S.String)
|
|
2382
|
+
});
|
|
2383
|
+
var PromptConfigSchema = S.Struct({
|
|
2384
|
+
systemPrompt: S.optional(S.String),
|
|
2385
|
+
phases: S.optional(PhasePromptOverridesSchema),
|
|
2386
|
+
additionalContext: S.optional(S.String)
|
|
2387
|
+
});
|
|
2388
|
+
var LoopConfigSchema = S.Struct({
|
|
2389
|
+
task: S.String,
|
|
2390
|
+
maxIterations: S.Number,
|
|
2391
|
+
verifyCommands: S.Array(S.String),
|
|
2392
|
+
sessionId: S.optional(S.String),
|
|
2393
|
+
branch: S.optional(S.String),
|
|
2394
|
+
push: S.optional(S.Boolean),
|
|
2395
|
+
pr: S.optional(S.Boolean),
|
|
2396
|
+
verbose: S.optional(S.Boolean),
|
|
2397
|
+
prompts: S.optional(PromptConfigSchema)
|
|
2398
|
+
});
|
|
2399
|
+
var LoopSummarySchema = S.Struct({
|
|
2400
|
+
iterations: S.Number,
|
|
2401
|
+
success: S.Boolean,
|
|
2402
|
+
sessionId: S.String,
|
|
2403
|
+
completedTasks: S.Array(S.String),
|
|
2404
|
+
durationMs: S.Number
|
|
2405
|
+
});
|
|
2406
|
+
var LoopErrorSchema = S.Struct({
|
|
2407
|
+
message: S.String,
|
|
2408
|
+
phase: S.String,
|
|
2409
|
+
iteration: S.optional(S.Number)
|
|
2410
|
+
});
|
|
2411
|
+
var decodeLoopConfig = S.decodeUnknown(LoopConfigSchema);
|
|
2543
2412
|
|
|
2544
|
-
// src/
|
|
2413
|
+
// src/domain/schemas/events.ts
|
|
2545
2414
|
init_esm_shims();
|
|
2546
|
-
import {
|
|
2415
|
+
import { Schema as S4 } from "effect";
|
|
2547
2416
|
|
|
2548
|
-
// src/domain/schemas/
|
|
2417
|
+
// src/domain/schemas/plan.ts
|
|
2549
2418
|
init_esm_shims();
|
|
2550
|
-
import { Schema as
|
|
2551
|
-
var
|
|
2552
|
-
|
|
2419
|
+
import { Brand, Schema as S2 } from "effect";
|
|
2420
|
+
var PlanId = Brand.nominal();
|
|
2421
|
+
var TaskStatusSchema = S2.Literal(
|
|
2422
|
+
"pending",
|
|
2423
|
+
"planning",
|
|
2424
|
+
"in_progress",
|
|
2425
|
+
"done",
|
|
2426
|
+
"failed",
|
|
2427
|
+
"skipped"
|
|
2428
|
+
);
|
|
2429
|
+
var PhaseStatusSchema = S2.Literal(
|
|
2430
|
+
"pending",
|
|
2431
|
+
"in_progress",
|
|
2432
|
+
"done",
|
|
2433
|
+
"failed"
|
|
2434
|
+
);
|
|
2435
|
+
var CriterionStatusSchema = S2.Literal("pending", "passed", "failed");
|
|
2436
|
+
var PhaseSchema = S2.Struct({
|
|
2437
|
+
id: S2.String,
|
|
2438
|
+
description: S2.String,
|
|
2439
|
+
status: PhaseStatusSchema
|
|
2553
2440
|
});
|
|
2554
|
-
var
|
|
2555
|
-
|
|
2441
|
+
var CriterionSchema = S2.Struct({
|
|
2442
|
+
id: S2.String,
|
|
2443
|
+
description: S2.String,
|
|
2444
|
+
status: CriterionStatusSchema,
|
|
2445
|
+
failureReason: S2.optional(S2.String)
|
|
2556
2446
|
});
|
|
2557
|
-
var
|
|
2558
|
-
|
|
2559
|
-
|
|
2447
|
+
var TaskSchema = S2.Struct({
|
|
2448
|
+
id: S2.String,
|
|
2449
|
+
title: S2.String,
|
|
2450
|
+
description: S2.String,
|
|
2451
|
+
status: TaskStatusSchema,
|
|
2452
|
+
phases: S2.Array(PhaseSchema),
|
|
2453
|
+
criteria: S2.Array(CriterionSchema),
|
|
2454
|
+
filesToModify: S2.Array(S2.String),
|
|
2455
|
+
attempts: S2.Number,
|
|
2456
|
+
completionNotes: S2.optional(S2.String)
|
|
2457
|
+
});
|
|
2458
|
+
var PlanDataSchema = S2.Struct({
|
|
2459
|
+
sessionId: S2.String,
|
|
2460
|
+
createdAt: S2.String,
|
|
2461
|
+
originalTask: S2.String,
|
|
2462
|
+
context: S2.optional(S2.String),
|
|
2463
|
+
tasks: S2.Array(TaskSchema)
|
|
2464
|
+
});
|
|
2465
|
+
var PlanSchema = S2.Struct({
|
|
2466
|
+
id: S2.String,
|
|
2467
|
+
sessionId: S2.String,
|
|
2468
|
+
createdAt: S2.String,
|
|
2469
|
+
originalTask: S2.String,
|
|
2470
|
+
context: S2.optional(S2.String),
|
|
2471
|
+
tasks: S2.Array(TaskSchema)
|
|
2472
|
+
});
|
|
2473
|
+
var decodePlan = S2.decodeUnknown(PlanSchema);
|
|
2474
|
+
var decodePlanData = S2.decodeUnknown(PlanDataSchema);
|
|
2475
|
+
|
|
2476
|
+
// src/domain/schemas/shared.ts
|
|
2477
|
+
init_esm_shims();
|
|
2478
|
+
import { Schema as S3 } from "effect";
|
|
2479
|
+
var TaskBasicInfoSchema = S3.Struct({
|
|
2480
|
+
id: S3.String,
|
|
2481
|
+
title: S3.String,
|
|
2482
|
+
description: S3.String
|
|
2560
2483
|
});
|
|
2561
|
-
var
|
|
2562
|
-
|
|
2484
|
+
var PhaseBasicInfoSchema = S3.Struct({
|
|
2485
|
+
id: S3.String,
|
|
2486
|
+
description: S3.String
|
|
2563
2487
|
});
|
|
2564
|
-
var
|
|
2565
|
-
|
|
2488
|
+
var CriterionBasicInfoSchema = S3.Struct({
|
|
2489
|
+
id: S3.String,
|
|
2490
|
+
description: S3.String
|
|
2566
2491
|
});
|
|
2567
|
-
var
|
|
2568
|
-
|
|
2569
|
-
ToolStartEventSchema,
|
|
2570
|
-
ToolUseEventSchema,
|
|
2571
|
-
ToolEndEventSchema,
|
|
2572
|
-
DoneEventSchema
|
|
2573
|
-
);
|
|
2574
|
-
var decodeLLMEvent = S.decodeUnknown(LLMEventSchema);
|
|
2575
|
-
|
|
2576
|
-
// src/layers/llm/mock.ts
|
|
2577
|
-
var MockLLMConfigSchema = S2.Struct({
|
|
2578
|
-
events: S2.Array(LLMEventSchema),
|
|
2579
|
-
delayMs: S2.optional(S2.Number)
|
|
2580
|
-
});
|
|
2581
|
-
function createMockLLM(config) {
|
|
2582
|
-
return {
|
|
2583
|
-
execute: (_prompt) => {
|
|
2584
|
-
const baseStream = Stream6.fromIterable(config.events);
|
|
2585
|
-
if (config.delayMs !== void 0 && config.delayMs > 0) {
|
|
2586
|
-
const delay = config.delayMs;
|
|
2587
|
-
return baseStream.pipe(Stream6.tap(() => Effect6.sleep(delay)));
|
|
2588
|
-
}
|
|
2589
|
-
return baseStream;
|
|
2590
|
-
}
|
|
2591
|
-
};
|
|
2592
|
-
}
|
|
2593
|
-
var defaultMockEvents = [
|
|
2594
|
-
{ _tag: "Text", text: "Processing task...\n" },
|
|
2595
|
-
{ _tag: "ToolStart", tool: "Read" },
|
|
2596
|
-
{ _tag: "ToolEnd", tool: "Read" },
|
|
2597
|
-
{ _tag: "Text", text: "Task completed successfully.\n" },
|
|
2598
|
-
{
|
|
2599
|
-
_tag: "Done",
|
|
2600
|
-
output: "Processing task...\nTask completed successfully.\n"
|
|
2601
|
-
}
|
|
2602
|
-
];
|
|
2603
|
-
var defaultMock = createMockLLM({ events: defaultMockEvents });
|
|
2604
|
-
var Live2 = Layer2.succeed(LLM, defaultMock);
|
|
2605
|
-
function layer(config) {
|
|
2606
|
-
return Layer2.succeed(LLM, createMockLLM(config));
|
|
2607
|
-
}
|
|
2608
|
-
var Mock = {
|
|
2609
|
-
Live: Live2,
|
|
2610
|
-
layer,
|
|
2611
|
-
createMockLLM
|
|
2612
|
-
};
|
|
2613
|
-
|
|
2614
|
-
// src/layers/plan/file-system.ts
|
|
2615
|
-
init_esm_shims();
|
|
2616
|
-
import { access, mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
2617
|
-
import { join } from "path";
|
|
2618
|
-
import { Effect as Effect7, Layer as Layer3 } from "effect";
|
|
2619
|
-
|
|
2620
|
-
// src/domain/index.ts
|
|
2621
|
-
init_esm_shims();
|
|
2622
|
-
|
|
2623
|
-
// src/domain/schemas/index.ts
|
|
2624
|
-
init_esm_shims();
|
|
2625
|
-
|
|
2626
|
-
// src/domain/schemas/config.ts
|
|
2627
|
-
init_esm_shims();
|
|
2628
|
-
import { Schema as S3 } from "effect";
|
|
2629
|
-
var PhasePromptOverridesSchema = S3.Struct({
|
|
2630
|
-
breakdown: S3.optional(S3.String),
|
|
2631
|
-
planning: S3.optional(S3.String),
|
|
2632
|
-
execution: S3.optional(S3.String),
|
|
2633
|
-
check: S3.optional(S3.String),
|
|
2634
|
-
verify: S3.optional(S3.String),
|
|
2635
|
-
review: S3.optional(S3.String),
|
|
2636
|
-
completion: S3.optional(S3.String)
|
|
2637
|
-
});
|
|
2638
|
-
var PromptConfigSchema = S3.Struct({
|
|
2639
|
-
systemPrompt: S3.optional(S3.String),
|
|
2640
|
-
phases: S3.optional(PhasePromptOverridesSchema),
|
|
2641
|
-
additionalContext: S3.optional(S3.String)
|
|
2642
|
-
});
|
|
2643
|
-
var LoopConfigSchema = S3.Struct({
|
|
2644
|
-
task: S3.String,
|
|
2645
|
-
maxIterations: S3.Number,
|
|
2646
|
-
verifyCommands: S3.Array(S3.String),
|
|
2647
|
-
sessionId: S3.optional(S3.String),
|
|
2648
|
-
branch: S3.optional(S3.String),
|
|
2649
|
-
push: S3.optional(S3.Boolean),
|
|
2650
|
-
pr: S3.optional(S3.Boolean),
|
|
2651
|
-
verbose: S3.optional(S3.Boolean),
|
|
2652
|
-
prompts: S3.optional(PromptConfigSchema)
|
|
2653
|
-
});
|
|
2654
|
-
var LoopSummarySchema = S3.Struct({
|
|
2655
|
-
iterations: S3.Number,
|
|
2656
|
-
success: S3.Boolean,
|
|
2657
|
-
sessionId: S3.String,
|
|
2658
|
-
completedTasks: S3.Array(S3.String),
|
|
2659
|
-
durationMs: S3.Number
|
|
2660
|
-
});
|
|
2661
|
-
var LoopErrorSchema = S3.Struct({
|
|
2662
|
-
message: S3.String,
|
|
2663
|
-
phase: S3.String,
|
|
2664
|
-
iteration: S3.optional(S3.Number)
|
|
2665
|
-
});
|
|
2666
|
-
var decodeLoopConfig = S3.decodeUnknown(LoopConfigSchema);
|
|
2667
|
-
|
|
2668
|
-
// src/domain/schemas/events.ts
|
|
2669
|
-
init_esm_shims();
|
|
2670
|
-
import { Schema as S6 } from "effect";
|
|
2671
|
-
|
|
2672
|
-
// src/domain/schemas/plan.ts
|
|
2673
|
-
init_esm_shims();
|
|
2674
|
-
import { Brand, Schema as S4 } from "effect";
|
|
2675
|
-
var PlanId = Brand.nominal();
|
|
2676
|
-
var TaskStatusSchema = S4.Literal(
|
|
2677
|
-
"pending",
|
|
2678
|
-
"planning",
|
|
2679
|
-
"in_progress",
|
|
2680
|
-
"done",
|
|
2681
|
-
"failed",
|
|
2682
|
-
"skipped"
|
|
2683
|
-
);
|
|
2684
|
-
var PhaseStatusSchema = S4.Literal(
|
|
2685
|
-
"pending",
|
|
2686
|
-
"in_progress",
|
|
2687
|
-
"done",
|
|
2688
|
-
"failed"
|
|
2689
|
-
);
|
|
2690
|
-
var CriterionStatusSchema = S4.Literal("pending", "passed", "failed");
|
|
2691
|
-
var PhaseSchema = S4.Struct({
|
|
2692
|
-
id: S4.String,
|
|
2693
|
-
description: S4.String,
|
|
2694
|
-
status: PhaseStatusSchema
|
|
2492
|
+
var TasksDefinedDataSchema = S3.Struct({
|
|
2493
|
+
tasks: S3.Array(TaskBasicInfoSchema)
|
|
2695
2494
|
});
|
|
2696
|
-
var
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
status: CriterionStatusSchema,
|
|
2700
|
-
failureReason: S4.optional(S4.String)
|
|
2495
|
+
var PhasesDefinedDataSchema = S3.Struct({
|
|
2496
|
+
taskId: S3.String,
|
|
2497
|
+
phases: S3.Array(PhaseBasicInfoSchema)
|
|
2701
2498
|
});
|
|
2702
|
-
var
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
description: S4.String,
|
|
2706
|
-
status: TaskStatusSchema,
|
|
2707
|
-
phases: S4.Array(PhaseSchema),
|
|
2708
|
-
criteria: S4.Array(CriterionSchema),
|
|
2709
|
-
filesToModify: S4.Array(S4.String),
|
|
2710
|
-
attempts: S4.Number,
|
|
2711
|
-
completionNotes: S4.optional(S4.String)
|
|
2499
|
+
var CriteriaDefinedDataSchema = S3.Struct({
|
|
2500
|
+
taskId: S3.String,
|
|
2501
|
+
criteria: S3.Array(CriterionBasicInfoSchema)
|
|
2712
2502
|
});
|
|
2713
|
-
var
|
|
2714
|
-
|
|
2715
|
-
createdAt: S4.String,
|
|
2716
|
-
originalTask: S4.String,
|
|
2717
|
-
context: S4.optional(S4.String),
|
|
2718
|
-
tasks: S4.Array(TaskSchema)
|
|
2503
|
+
var PhaseIdDataSchema = S3.Struct({
|
|
2504
|
+
phaseId: S3.String
|
|
2719
2505
|
});
|
|
2720
|
-
var
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
createdAt: S4.String,
|
|
2724
|
-
originalTask: S4.String,
|
|
2725
|
-
context: S4.optional(S4.String),
|
|
2726
|
-
tasks: S4.Array(TaskSchema)
|
|
2506
|
+
var PhaseFailedDataSchema = S3.Struct({
|
|
2507
|
+
phaseId: S3.String,
|
|
2508
|
+
reason: S3.String
|
|
2727
2509
|
});
|
|
2728
|
-
var
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
// src/domain/schemas/shared.ts
|
|
2732
|
-
init_esm_shims();
|
|
2733
|
-
import { Schema as S5 } from "effect";
|
|
2734
|
-
var TaskBasicInfoSchema = S5.Struct({
|
|
2735
|
-
id: S5.String,
|
|
2736
|
-
title: S5.String,
|
|
2737
|
-
description: S5.String
|
|
2738
|
-
});
|
|
2739
|
-
var PhaseBasicInfoSchema = S5.Struct({
|
|
2740
|
-
id: S5.String,
|
|
2741
|
-
description: S5.String
|
|
2742
|
-
});
|
|
2743
|
-
var CriterionBasicInfoSchema = S5.Struct({
|
|
2744
|
-
id: S5.String,
|
|
2745
|
-
description: S5.String
|
|
2746
|
-
});
|
|
2747
|
-
var TasksDefinedDataSchema = S5.Struct({
|
|
2748
|
-
tasks: S5.Array(TaskBasicInfoSchema)
|
|
2510
|
+
var CriterionIdDataSchema = S3.Struct({
|
|
2511
|
+
criterionId: S3.String
|
|
2749
2512
|
});
|
|
2750
|
-
var
|
|
2751
|
-
|
|
2752
|
-
|
|
2513
|
+
var CriterionFailedDataSchema = S3.Struct({
|
|
2514
|
+
criterionId: S3.String,
|
|
2515
|
+
reason: S3.String
|
|
2753
2516
|
});
|
|
2754
|
-
var
|
|
2755
|
-
|
|
2756
|
-
criteria: S5.Array(CriterionBasicInfoSchema)
|
|
2517
|
+
var ReviewCompleteDataSchema = S3.Struct({
|
|
2518
|
+
changesMade: S3.Boolean
|
|
2757
2519
|
});
|
|
2758
|
-
var
|
|
2759
|
-
|
|
2520
|
+
var TaskCompleteSignalDataSchema = S3.Struct({
|
|
2521
|
+
taskId: S3.String,
|
|
2522
|
+
summary: S3.String,
|
|
2523
|
+
filesModified: S3.Array(S3.String),
|
|
2524
|
+
filesCreated: S3.Array(S3.String)
|
|
2760
2525
|
});
|
|
2761
|
-
var
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
});
|
|
2765
|
-
var CriterionIdDataSchema = S5.Struct({
|
|
2766
|
-
criterionId: S5.String
|
|
2767
|
-
});
|
|
2768
|
-
var CriterionFailedDataSchema = S5.Struct({
|
|
2769
|
-
criterionId: S5.String,
|
|
2770
|
-
reason: S5.String
|
|
2771
|
-
});
|
|
2772
|
-
var ReviewCompleteDataSchema = S5.Struct({
|
|
2773
|
-
changesMade: S5.Boolean
|
|
2774
|
-
});
|
|
2775
|
-
var TaskCompleteSignalDataSchema = S5.Struct({
|
|
2776
|
-
taskId: S5.String,
|
|
2777
|
-
summary: S5.String,
|
|
2778
|
-
filesModified: S5.Array(S5.String),
|
|
2779
|
-
filesCreated: S5.Array(S5.String)
|
|
2780
|
-
});
|
|
2781
|
-
var TaskCompleteDataSchema = S5.Struct({
|
|
2782
|
-
taskId: S5.String,
|
|
2783
|
-
summary: S5.String
|
|
2526
|
+
var TaskCompleteDataSchema = S3.Struct({
|
|
2527
|
+
taskId: S3.String,
|
|
2528
|
+
summary: S3.String
|
|
2784
2529
|
});
|
|
2785
2530
|
|
|
2786
2531
|
// src/domain/schemas/events.ts
|
|
2787
|
-
var taggedEvent = (tag, fields) =>
|
|
2788
|
-
var taggedFromData = (tag, dataSchema, extraFields = {}) =>
|
|
2532
|
+
var taggedEvent = (tag, fields) => S4.TaggedStruct(tag, fields);
|
|
2533
|
+
var taggedFromData = (tag, dataSchema, extraFields = {}) => S4.TaggedStruct(tag, { ...dataSchema.fields, ...extraFields });
|
|
2789
2534
|
var LoopStartedEventSchema = taggedEvent("LoopStarted", {
|
|
2790
2535
|
config: LoopConfigSchema,
|
|
2791
|
-
timestamp:
|
|
2536
|
+
timestamp: S4.Number
|
|
2792
2537
|
});
|
|
2793
2538
|
var LoopCompletedEventSchema = taggedEvent("LoopCompleted", {
|
|
2794
2539
|
summary: LoopSummarySchema
|
|
@@ -2797,30 +2542,30 @@ var LoopFailedEventSchema = taggedEvent("LoopFailed", {
|
|
|
2797
2542
|
error: LoopErrorSchema
|
|
2798
2543
|
});
|
|
2799
2544
|
var DiscoveryStartedEventSchema = taggedEvent("DiscoveryStarted", {
|
|
2800
|
-
timestamp:
|
|
2545
|
+
timestamp: S4.Number
|
|
2801
2546
|
});
|
|
2802
2547
|
var DiscoveryCompletedEventSchema = taggedEvent("DiscoveryCompleted", {
|
|
2803
|
-
taskCount:
|
|
2804
|
-
timestamp:
|
|
2548
|
+
taskCount: S4.Number,
|
|
2549
|
+
timestamp: S4.Number
|
|
2805
2550
|
});
|
|
2806
2551
|
var IterationStartedEventSchema = taggedEvent("IterationStarted", {
|
|
2807
|
-
iteration:
|
|
2552
|
+
iteration: S4.Number
|
|
2808
2553
|
});
|
|
2809
2554
|
var IterationCompletedEventSchema = taggedEvent("IterationCompleted", {
|
|
2810
|
-
iteration:
|
|
2555
|
+
iteration: S4.Number
|
|
2811
2556
|
});
|
|
2812
2557
|
var LLMTextEventSchema = taggedEvent("LLMText", {
|
|
2813
|
-
text:
|
|
2558
|
+
text: S4.String
|
|
2814
2559
|
});
|
|
2815
2560
|
var LLMToolStartEventSchema = taggedEvent("LLMToolStart", {
|
|
2816
|
-
tool:
|
|
2561
|
+
tool: S4.String
|
|
2817
2562
|
});
|
|
2818
2563
|
var LLMToolUseEventSchema = taggedEvent("LLMToolUse", {
|
|
2819
|
-
tool:
|
|
2820
|
-
input:
|
|
2564
|
+
tool: S4.String,
|
|
2565
|
+
input: S4.Unknown
|
|
2821
2566
|
});
|
|
2822
2567
|
var LLMToolEndEventSchema = taggedEvent("LLMToolEnd", {
|
|
2823
|
-
tool:
|
|
2568
|
+
tool: S4.String
|
|
2824
2569
|
});
|
|
2825
2570
|
var TasksDefinedEventSchema = taggedFromData(
|
|
2826
2571
|
"TasksDefined",
|
|
@@ -2837,17 +2582,17 @@ var CriteriaDefinedEventSchema = taggedFromData(
|
|
|
2837
2582
|
var PhaseStartedEventSchema = taggedFromData(
|
|
2838
2583
|
"PhaseStarted",
|
|
2839
2584
|
PhaseIdDataSchema,
|
|
2840
|
-
{ timestamp:
|
|
2585
|
+
{ timestamp: S4.Number }
|
|
2841
2586
|
);
|
|
2842
2587
|
var PhaseCompletedEventSchema = taggedFromData(
|
|
2843
2588
|
"PhaseCompleted",
|
|
2844
2589
|
PhaseIdDataSchema,
|
|
2845
|
-
{ timestamp:
|
|
2590
|
+
{ timestamp: S4.Number }
|
|
2846
2591
|
);
|
|
2847
2592
|
var PhaseFailedEventSchema = taggedFromData(
|
|
2848
2593
|
"PhaseFailed",
|
|
2849
2594
|
PhaseFailedDataSchema,
|
|
2850
|
-
{ timestamp:
|
|
2595
|
+
{ timestamp: S4.Number }
|
|
2851
2596
|
);
|
|
2852
2597
|
var CriterionPassedEventSchema = taggedFromData(
|
|
2853
2598
|
"CriterionPassed",
|
|
@@ -2857,9 +2602,9 @@ var CriterionFailedEventSchema = taggedFromData(
|
|
|
2857
2602
|
"CriterionFailed",
|
|
2858
2603
|
CriterionFailedDataSchema
|
|
2859
2604
|
);
|
|
2860
|
-
var CheckPassedEventSchema =
|
|
2605
|
+
var CheckPassedEventSchema = S4.TaggedStruct("CheckPassed", {});
|
|
2861
2606
|
var CheckFailedEventSchema = taggedEvent("CheckFailed", {
|
|
2862
|
-
failedCriteria:
|
|
2607
|
+
failedCriteria: S4.Array(S4.String)
|
|
2863
2608
|
});
|
|
2864
2609
|
var ReviewCompleteEventSchema = taggedFromData(
|
|
2865
2610
|
"ReviewComplete",
|
|
@@ -2868,7 +2613,7 @@ var ReviewCompleteEventSchema = taggedFromData(
|
|
|
2868
2613
|
var TaskCompletedEventSchema = taggedFromData(
|
|
2869
2614
|
"TaskCompleted",
|
|
2870
2615
|
TaskCompleteDataSchema,
|
|
2871
|
-
{ timestamp:
|
|
2616
|
+
{ timestamp: S4.Number }
|
|
2872
2617
|
);
|
|
2873
2618
|
var PlanCreatedEventSchema = taggedEvent("PlanCreated", {
|
|
2874
2619
|
plan: PlanSchema
|
|
@@ -2877,11 +2622,33 @@ var PlanUpdatedEventSchema = taggedEvent("PlanUpdated", {
|
|
|
2877
2622
|
plan: PlanSchema
|
|
2878
2623
|
});
|
|
2879
2624
|
var PlanUpdateFailedEventSchema = taggedEvent("PlanUpdateFailed", {
|
|
2880
|
-
operation:
|
|
2881
|
-
error:
|
|
2882
|
-
planId:
|
|
2625
|
+
operation: S4.Literal("create", "update"),
|
|
2626
|
+
error: S4.String,
|
|
2627
|
+
planId: S4.optional(S4.String)
|
|
2628
|
+
});
|
|
2629
|
+
var LearningRecordedEventSchema = taggedEvent("LearningRecorded", {
|
|
2630
|
+
iteration: S4.Number,
|
|
2631
|
+
content: S4.String,
|
|
2632
|
+
category: S4.optional(S4.Literal("success", "failure", "optimization")),
|
|
2633
|
+
timestamp: S4.Number
|
|
2883
2634
|
});
|
|
2884
|
-
var
|
|
2635
|
+
var GuardrailAddedEventSchema = taggedEvent("GuardrailAdded", {
|
|
2636
|
+
id: S4.String,
|
|
2637
|
+
iteration: S4.Number,
|
|
2638
|
+
pattern: S4.String,
|
|
2639
|
+
sign: S4.String,
|
|
2640
|
+
avoidance: S4.String,
|
|
2641
|
+
severity: S4.Literal("warning", "critical"),
|
|
2642
|
+
timestamp: S4.Number
|
|
2643
|
+
});
|
|
2644
|
+
var ProgressUpdatedEventSchema = taggedEvent("ProgressUpdated", {
|
|
2645
|
+
sessionId: S4.String,
|
|
2646
|
+
iteration: S4.Number,
|
|
2647
|
+
taskId: S4.String,
|
|
2648
|
+
action: S4.Literal("started", "completed", "failed", "learning"),
|
|
2649
|
+
timestamp: S4.Number
|
|
2650
|
+
});
|
|
2651
|
+
var DomainEventSchema = S4.Union(
|
|
2885
2652
|
LoopStartedEventSchema,
|
|
2886
2653
|
LoopCompletedEventSchema,
|
|
2887
2654
|
LoopFailedEventSchema,
|
|
@@ -2907,7 +2674,10 @@ var DomainEventSchema = S6.Union(
|
|
|
2907
2674
|
TaskCompletedEventSchema,
|
|
2908
2675
|
PlanCreatedEventSchema,
|
|
2909
2676
|
PlanUpdatedEventSchema,
|
|
2910
|
-
PlanUpdateFailedEventSchema
|
|
2677
|
+
PlanUpdateFailedEventSchema,
|
|
2678
|
+
LearningRecordedEventSchema,
|
|
2679
|
+
GuardrailAddedEventSchema,
|
|
2680
|
+
ProgressUpdatedEventSchema
|
|
2911
2681
|
);
|
|
2912
2682
|
var DomainEventUtils = {
|
|
2913
2683
|
isLLMEvent: (e) => e._tag.startsWith("LLM"),
|
|
@@ -2917,6 +2687,55 @@ var DomainEventUtils = {
|
|
|
2917
2687
|
isDiscoveryEvent: (e) => e._tag.startsWith("Discovery")
|
|
2918
2688
|
};
|
|
2919
2689
|
|
|
2690
|
+
// src/domain/schemas/guardrails.ts
|
|
2691
|
+
init_esm_shims();
|
|
2692
|
+
import { Schema as S5 } from "effect";
|
|
2693
|
+
var GuardrailSeveritySchema = S5.Literal("warning", "critical");
|
|
2694
|
+
var GuardrailSchema = S5.Struct({
|
|
2695
|
+
id: S5.String,
|
|
2696
|
+
createdAt: S5.String,
|
|
2697
|
+
iteration: S5.Number,
|
|
2698
|
+
pattern: S5.String,
|
|
2699
|
+
sign: S5.String,
|
|
2700
|
+
avoidance: S5.String,
|
|
2701
|
+
severity: GuardrailSeveritySchema
|
|
2702
|
+
});
|
|
2703
|
+
var GuardrailsFileSchema = S5.Struct({
|
|
2704
|
+
sessionId: S5.String,
|
|
2705
|
+
createdAt: S5.String,
|
|
2706
|
+
guardrails: S5.Array(GuardrailSchema)
|
|
2707
|
+
});
|
|
2708
|
+
var decodeGuardrail = S5.decodeUnknown(GuardrailSchema);
|
|
2709
|
+
var decodeGuardrailsFile = S5.decodeUnknown(GuardrailsFileSchema);
|
|
2710
|
+
|
|
2711
|
+
// src/domain/schemas/llm.ts
|
|
2712
|
+
init_esm_shims();
|
|
2713
|
+
import { Schema as S6 } from "effect";
|
|
2714
|
+
var TextEventSchema = S6.TaggedStruct("Text", {
|
|
2715
|
+
text: S6.String
|
|
2716
|
+
});
|
|
2717
|
+
var ToolStartEventSchema = S6.TaggedStruct("ToolStart", {
|
|
2718
|
+
tool: S6.String
|
|
2719
|
+
});
|
|
2720
|
+
var ToolUseEventSchema = S6.TaggedStruct("ToolUse", {
|
|
2721
|
+
tool: S6.String,
|
|
2722
|
+
input: S6.Unknown
|
|
2723
|
+
});
|
|
2724
|
+
var ToolEndEventSchema = S6.TaggedStruct("ToolEnd", {
|
|
2725
|
+
tool: S6.String
|
|
2726
|
+
});
|
|
2727
|
+
var DoneEventSchema = S6.TaggedStruct("Done", {
|
|
2728
|
+
output: S6.String
|
|
2729
|
+
});
|
|
2730
|
+
var LLMEventSchema = S6.Union(
|
|
2731
|
+
TextEventSchema,
|
|
2732
|
+
ToolStartEventSchema,
|
|
2733
|
+
ToolUseEventSchema,
|
|
2734
|
+
ToolEndEventSchema,
|
|
2735
|
+
DoneEventSchema
|
|
2736
|
+
);
|
|
2737
|
+
var decodeLLMEvent = S6.decodeUnknown(LLMEventSchema);
|
|
2738
|
+
|
|
2920
2739
|
// src/domain/schemas/logger.ts
|
|
2921
2740
|
init_esm_shims();
|
|
2922
2741
|
import { Schema as S7 } from "effect";
|
|
@@ -2945,29 +2764,55 @@ var RunOptionsDataSchema = S8.Struct({
|
|
|
2945
2764
|
consumer: S8.optional(ConsumerTypeSchema)
|
|
2946
2765
|
});
|
|
2947
2766
|
|
|
2948
|
-
// src/domain/schemas/
|
|
2767
|
+
// src/domain/schemas/progress.ts
|
|
2949
2768
|
init_esm_shims();
|
|
2950
2769
|
import { Schema as S9 } from "effect";
|
|
2951
|
-
var
|
|
2770
|
+
var ProgressActionSchema = S9.Literal(
|
|
2771
|
+
"started",
|
|
2772
|
+
"completed",
|
|
2773
|
+
"failed",
|
|
2774
|
+
"learning"
|
|
2775
|
+
);
|
|
2776
|
+
var ProgressEntrySchema = S9.Struct({
|
|
2777
|
+
iteration: S9.Number,
|
|
2778
|
+
timestamp: S9.String,
|
|
2779
|
+
taskId: S9.String,
|
|
2780
|
+
action: ProgressActionSchema,
|
|
2781
|
+
summary: S9.String,
|
|
2782
|
+
learnings: S9.optional(S9.Array(S9.String)),
|
|
2783
|
+
filesModified: S9.optional(S9.Array(S9.String))
|
|
2784
|
+
});
|
|
2785
|
+
var ProgressFileSchema = S9.Struct({
|
|
2786
|
+
sessionId: S9.String,
|
|
2787
|
+
createdAt: S9.String,
|
|
2788
|
+
entries: S9.Array(ProgressEntrySchema)
|
|
2789
|
+
});
|
|
2790
|
+
var decodeProgressEntry = S9.decodeUnknown(ProgressEntrySchema);
|
|
2791
|
+
var decodeProgressFile = S9.decodeUnknown(ProgressFileSchema);
|
|
2792
|
+
|
|
2793
|
+
// src/domain/schemas/session.ts
|
|
2794
|
+
init_esm_shims();
|
|
2795
|
+
import { Schema as S10 } from "effect";
|
|
2796
|
+
var SessionStatusSchema = S10.Literal(
|
|
2952
2797
|
"active",
|
|
2953
2798
|
"completed",
|
|
2954
2799
|
"failed",
|
|
2955
2800
|
"paused"
|
|
2956
2801
|
);
|
|
2957
|
-
var SessionSchema =
|
|
2958
|
-
id:
|
|
2959
|
-
createdAt:
|
|
2802
|
+
var SessionSchema = S10.Struct({
|
|
2803
|
+
id: S10.String,
|
|
2804
|
+
createdAt: S10.String,
|
|
2960
2805
|
status: SessionStatusSchema,
|
|
2961
|
-
originalTask:
|
|
2962
|
-
completedTasks:
|
|
2963
|
-
currentTaskId:
|
|
2806
|
+
originalTask: S10.String,
|
|
2807
|
+
completedTasks: S10.Array(S10.String),
|
|
2808
|
+
currentTaskId: S10.optional(S10.String)
|
|
2964
2809
|
});
|
|
2965
|
-
var decodeSession =
|
|
2810
|
+
var decodeSession = S10.decodeUnknown(SessionSchema);
|
|
2966
2811
|
|
|
2967
2812
|
// src/domain/schemas/signals.ts
|
|
2968
2813
|
init_esm_shims();
|
|
2969
|
-
import { Schema as
|
|
2970
|
-
var taggedFromData2 = (tag, dataSchema) =>
|
|
2814
|
+
import { Schema as S11 } from "effect";
|
|
2815
|
+
var taggedFromData2 = (tag, dataSchema) => S11.TaggedStruct(tag, dataSchema.fields);
|
|
2971
2816
|
var TasksDefinedSignalSchema = taggedFromData2(
|
|
2972
2817
|
"TasksDefined",
|
|
2973
2818
|
TasksDefinedDataSchema
|
|
@@ -3000,8 +2845,8 @@ var CriterionFailedSignalSchema = taggedFromData2(
|
|
|
3000
2845
|
"CriterionFailed",
|
|
3001
2846
|
CriterionFailedDataSchema
|
|
3002
2847
|
);
|
|
3003
|
-
var CheckPassedSignalSchema =
|
|
3004
|
-
var CheckFailedSignalSchema =
|
|
2848
|
+
var CheckPassedSignalSchema = S11.TaggedStruct("CheckPassed", {});
|
|
2849
|
+
var CheckFailedSignalSchema = S11.TaggedStruct("CheckFailed", {});
|
|
3005
2850
|
var ReviewCompleteSignalSchema = taggedFromData2(
|
|
3006
2851
|
"ReviewComplete",
|
|
3007
2852
|
ReviewCompleteDataSchema
|
|
@@ -3010,8 +2855,23 @@ var TaskCompleteSignalSchema = taggedFromData2(
|
|
|
3010
2855
|
"TaskComplete",
|
|
3011
2856
|
TaskCompleteSignalDataSchema
|
|
3012
2857
|
);
|
|
3013
|
-
var LoopCompleteSignalSchema =
|
|
3014
|
-
var
|
|
2858
|
+
var LoopCompleteSignalSchema = S11.TaggedStruct("LoopComplete", {});
|
|
2859
|
+
var LearningCategorySchema = S11.Literal(
|
|
2860
|
+
"success",
|
|
2861
|
+
"failure",
|
|
2862
|
+
"optimization"
|
|
2863
|
+
);
|
|
2864
|
+
var LearningSignalSchema = S11.TaggedStruct("Learning", {
|
|
2865
|
+
content: S11.String,
|
|
2866
|
+
category: S11.optional(LearningCategorySchema)
|
|
2867
|
+
});
|
|
2868
|
+
var GuardrailSignalSchema = S11.TaggedStruct("Guardrail", {
|
|
2869
|
+
pattern: S11.String,
|
|
2870
|
+
sign: S11.String,
|
|
2871
|
+
avoidance: S11.String,
|
|
2872
|
+
severity: S11.Literal("warning", "critical")
|
|
2873
|
+
});
|
|
2874
|
+
var SignalSchema = S11.Union(
|
|
3015
2875
|
TasksDefinedSignalSchema,
|
|
3016
2876
|
PhasesDefinedSignalSchema,
|
|
3017
2877
|
CriteriaDefinedSignalSchema,
|
|
@@ -3024,26 +2884,28 @@ var SignalSchema = S10.Union(
|
|
|
3024
2884
|
CheckFailedSignalSchema,
|
|
3025
2885
|
ReviewCompleteSignalSchema,
|
|
3026
2886
|
TaskCompleteSignalSchema,
|
|
3027
|
-
LoopCompleteSignalSchema
|
|
2887
|
+
LoopCompleteSignalSchema,
|
|
2888
|
+
LearningSignalSchema,
|
|
2889
|
+
GuardrailSignalSchema
|
|
3028
2890
|
);
|
|
3029
|
-
var decodeSignal =
|
|
3030
|
-
var decodeSignalSync =
|
|
2891
|
+
var decodeSignal = S11.decodeUnknown(SignalSchema);
|
|
2892
|
+
var decodeSignalSync = S11.decodeUnknownSync(SignalSchema);
|
|
3031
2893
|
|
|
3032
2894
|
// src/domain/schemas/task-generation.ts
|
|
3033
2895
|
init_esm_shims();
|
|
3034
|
-
import { Schema as
|
|
3035
|
-
var GeneratedTaskStatusSchema =
|
|
2896
|
+
import { Schema as S12 } from "effect";
|
|
2897
|
+
var GeneratedTaskStatusSchema = S12.Literal(
|
|
3036
2898
|
"pending",
|
|
3037
2899
|
"in_progress",
|
|
3038
2900
|
"done",
|
|
3039
2901
|
"failed"
|
|
3040
2902
|
);
|
|
3041
|
-
var GeneratedTaskSchema =
|
|
3042
|
-
id:
|
|
3043
|
-
title:
|
|
2903
|
+
var GeneratedTaskSchema = S12.Struct({
|
|
2904
|
+
id: S12.String,
|
|
2905
|
+
title: S12.String,
|
|
3044
2906
|
status: GeneratedTaskStatusSchema
|
|
3045
2907
|
});
|
|
3046
|
-
var GeneratedTaskListSchema =
|
|
2908
|
+
var GeneratedTaskListSchema = S12.Array(GeneratedTaskSchema);
|
|
3047
2909
|
var STATUS_ICONS = {
|
|
3048
2910
|
done: "[x]",
|
|
3049
2911
|
in_progress: "[~]",
|
|
@@ -3102,15 +2964,15 @@ function parseTasksMd(content) {
|
|
|
3102
2964
|
|
|
3103
2965
|
// src/domain/schemas/tui.ts
|
|
3104
2966
|
init_esm_shims();
|
|
3105
|
-
import { Schema as
|
|
3106
|
-
var ViewModeSchema =
|
|
3107
|
-
var LoopStatusSchema =
|
|
2967
|
+
import { Schema as S13 } from "effect";
|
|
2968
|
+
var ViewModeSchema = S13.Literal("logs", "tasks", "detail");
|
|
2969
|
+
var LoopStatusSchema = S13.Literal(
|
|
3108
2970
|
"idle",
|
|
3109
2971
|
"running",
|
|
3110
2972
|
"complete",
|
|
3111
2973
|
"error"
|
|
3112
2974
|
);
|
|
3113
|
-
var ExecutionModeSchema =
|
|
2975
|
+
var ExecutionModeSchema = S13.Literal(
|
|
3114
2976
|
"idle",
|
|
3115
2977
|
"discovery",
|
|
3116
2978
|
"breakdown",
|
|
@@ -3120,98 +2982,565 @@ var ExecutionModeSchema = S12.Literal(
|
|
|
3120
2982
|
"verifying",
|
|
3121
2983
|
"reviewing"
|
|
3122
2984
|
);
|
|
3123
|
-
var TUIPhaseStatusSchema =
|
|
2985
|
+
var TUIPhaseStatusSchema = S13.Literal(
|
|
3124
2986
|
"pending",
|
|
3125
2987
|
"in_progress",
|
|
3126
2988
|
"done",
|
|
3127
2989
|
"failed"
|
|
3128
2990
|
);
|
|
3129
|
-
var TUICriterionStatusSchema =
|
|
2991
|
+
var TUICriterionStatusSchema = S13.Literal(
|
|
3130
2992
|
"pending",
|
|
3131
2993
|
"passed",
|
|
3132
2994
|
"failed"
|
|
3133
2995
|
);
|
|
3134
|
-
var TUITaskStatusSchema =
|
|
2996
|
+
var TUITaskStatusSchema = S13.Literal(
|
|
3135
2997
|
"pending",
|
|
3136
2998
|
"in_progress",
|
|
3137
2999
|
"done",
|
|
3138
3000
|
"failed"
|
|
3139
3001
|
);
|
|
3140
|
-
var TUIPhaseSchema =
|
|
3141
|
-
id:
|
|
3142
|
-
description:
|
|
3002
|
+
var TUIPhaseSchema = S13.Struct({
|
|
3003
|
+
id: S13.String,
|
|
3004
|
+
description: S13.String,
|
|
3143
3005
|
status: TUIPhaseStatusSchema,
|
|
3144
|
-
startedAt:
|
|
3145
|
-
completedAt:
|
|
3006
|
+
startedAt: S13.optional(S13.Number),
|
|
3007
|
+
completedAt: S13.optional(S13.Number)
|
|
3146
3008
|
});
|
|
3147
|
-
var TUICriterionSchema =
|
|
3148
|
-
id:
|
|
3149
|
-
description:
|
|
3009
|
+
var TUICriterionSchema = S13.Struct({
|
|
3010
|
+
id: S13.String,
|
|
3011
|
+
description: S13.String,
|
|
3150
3012
|
status: TUICriterionStatusSchema,
|
|
3151
|
-
failureReason:
|
|
3013
|
+
failureReason: S13.optional(S13.String)
|
|
3152
3014
|
});
|
|
3153
|
-
var TUITaskSchema =
|
|
3154
|
-
id:
|
|
3155
|
-
title:
|
|
3015
|
+
var TUITaskSchema = S13.Struct({
|
|
3016
|
+
id: S13.String,
|
|
3017
|
+
title: S13.String,
|
|
3156
3018
|
status: TUITaskStatusSchema,
|
|
3157
|
-
phases:
|
|
3158
|
-
criteria:
|
|
3159
|
-
startedAt:
|
|
3160
|
-
completedAt:
|
|
3019
|
+
phases: S13.Array(TUIPhaseSchema),
|
|
3020
|
+
criteria: S13.Array(TUICriterionSchema),
|
|
3021
|
+
startedAt: S13.optional(S13.Number),
|
|
3022
|
+
completedAt: S13.optional(S13.Number)
|
|
3161
3023
|
});
|
|
3162
|
-
var TUIStateSchema =
|
|
3024
|
+
var TUIStateSchema = S13.Struct({
|
|
3163
3025
|
// Loop info
|
|
3164
|
-
task:
|
|
3165
|
-
iteration:
|
|
3166
|
-
maxIterations:
|
|
3026
|
+
task: S13.String,
|
|
3027
|
+
iteration: S13.Number,
|
|
3028
|
+
maxIterations: S13.Number,
|
|
3167
3029
|
status: LoopStatusSchema,
|
|
3168
|
-
startTime:
|
|
3030
|
+
startTime: S13.Number,
|
|
3169
3031
|
// Discovery phase
|
|
3170
|
-
discoveryInProgress:
|
|
3171
|
-
discoveryCompleted:
|
|
3032
|
+
discoveryInProgress: S13.Boolean,
|
|
3033
|
+
discoveryCompleted: S13.Boolean,
|
|
3172
3034
|
// Current activity
|
|
3173
3035
|
executionMode: ExecutionModeSchema,
|
|
3174
|
-
currentTool:
|
|
3175
|
-
currentTaskId:
|
|
3036
|
+
currentTool: S13.optional(S13.String),
|
|
3037
|
+
currentTaskId: S13.optional(S13.String),
|
|
3176
3038
|
// Output
|
|
3177
|
-
outputLines:
|
|
3178
|
-
partialLine:
|
|
3039
|
+
outputLines: S13.Array(S13.String),
|
|
3040
|
+
partialLine: S13.String,
|
|
3179
3041
|
// Tasks
|
|
3180
|
-
tasks:
|
|
3042
|
+
tasks: S13.Array(TUITaskSchema),
|
|
3181
3043
|
// Navigation
|
|
3182
3044
|
viewMode: ViewModeSchema,
|
|
3183
|
-
selectedTaskIndex:
|
|
3184
|
-
scrollOffset:
|
|
3185
|
-
userScrolled:
|
|
3045
|
+
selectedTaskIndex: S13.Number,
|
|
3046
|
+
scrollOffset: S13.Number,
|
|
3047
|
+
userScrolled: S13.Boolean,
|
|
3186
3048
|
// Git
|
|
3187
|
-
gitBranch:
|
|
3188
|
-
gitPushed:
|
|
3189
|
-
prUrl:
|
|
3049
|
+
gitBranch: S13.optional(S13.String),
|
|
3050
|
+
gitPushed: S13.Boolean,
|
|
3051
|
+
prUrl: S13.optional(S13.String)
|
|
3052
|
+
});
|
|
3053
|
+
|
|
3054
|
+
// src/services/guardrails-store.ts
|
|
3055
|
+
init_esm_shims();
|
|
3056
|
+
import { Context } from "effect";
|
|
3057
|
+
var GuardrailsStore = class extends Context.Tag("@ferix/GuardrailsStore")() {
|
|
3058
|
+
};
|
|
3059
|
+
|
|
3060
|
+
// src/layers/guardrails/file-system.ts
|
|
3061
|
+
var PLANS_DIR = ".ferix/plans";
|
|
3062
|
+
function ensureDir(dirPath) {
|
|
3063
|
+
return Effect4.tryPromise({
|
|
3064
|
+
try: () => mkdir(dirPath, { recursive: true }),
|
|
3065
|
+
catch: (error) => new GuardrailsStoreError({
|
|
3066
|
+
message: `Failed to create directory: ${dirPath}`,
|
|
3067
|
+
operation: "add",
|
|
3068
|
+
cause: error
|
|
3069
|
+
})
|
|
3070
|
+
}).pipe(Effect4.asVoid);
|
|
3071
|
+
}
|
|
3072
|
+
function getSessionDir(sessionId) {
|
|
3073
|
+
return join(process.cwd(), PLANS_DIR, sessionId);
|
|
3074
|
+
}
|
|
3075
|
+
function getGuardrailsPath(sessionId) {
|
|
3076
|
+
return join(getSessionDir(sessionId), "guardrails.json");
|
|
3077
|
+
}
|
|
3078
|
+
function serializeGuardrails(guardrails) {
|
|
3079
|
+
return JSON.stringify(guardrails, null, 2);
|
|
3080
|
+
}
|
|
3081
|
+
function deserializeGuardrails(json) {
|
|
3082
|
+
return Effect4.gen(function* () {
|
|
3083
|
+
const parsed = yield* Effect4.try({
|
|
3084
|
+
try: () => JSON.parse(json),
|
|
3085
|
+
catch: (error) => new GuardrailsStoreError({
|
|
3086
|
+
message: `Invalid JSON in guardrails file: ${String(error)}`,
|
|
3087
|
+
operation: "load",
|
|
3088
|
+
cause: error
|
|
3089
|
+
})
|
|
3090
|
+
});
|
|
3091
|
+
const validated = yield* decodeGuardrailsFile(parsed).pipe(
|
|
3092
|
+
Effect4.mapError(
|
|
3093
|
+
(error) => new GuardrailsStoreError({
|
|
3094
|
+
message: `Guardrails validation failed: ${String(error)}`,
|
|
3095
|
+
operation: "load",
|
|
3096
|
+
cause: error
|
|
3097
|
+
})
|
|
3098
|
+
)
|
|
3099
|
+
);
|
|
3100
|
+
return validated;
|
|
3101
|
+
});
|
|
3102
|
+
}
|
|
3103
|
+
function createEmptyGuardrails(sessionId, createdAt) {
|
|
3104
|
+
return {
|
|
3105
|
+
sessionId,
|
|
3106
|
+
createdAt,
|
|
3107
|
+
guardrails: []
|
|
3108
|
+
};
|
|
3109
|
+
}
|
|
3110
|
+
var make = {
|
|
3111
|
+
add: (sessionId, guardrail) => Effect4.gen(function* () {
|
|
3112
|
+
const sessionDir = getSessionDir(sessionId);
|
|
3113
|
+
yield* ensureDir(sessionDir);
|
|
3114
|
+
const guardrailsPath = getGuardrailsPath(sessionId);
|
|
3115
|
+
const existing = yield* Effect4.tryPromise({
|
|
3116
|
+
try: async () => {
|
|
3117
|
+
try {
|
|
3118
|
+
const content = await readFile(guardrailsPath, "utf-8");
|
|
3119
|
+
return content;
|
|
3120
|
+
} catch {
|
|
3121
|
+
return null;
|
|
3122
|
+
}
|
|
3123
|
+
},
|
|
3124
|
+
catch: (error) => new GuardrailsStoreError({
|
|
3125
|
+
message: `Failed to read guardrails file: ${guardrailsPath}`,
|
|
3126
|
+
operation: "add",
|
|
3127
|
+
cause: error
|
|
3128
|
+
})
|
|
3129
|
+
});
|
|
3130
|
+
let guardrails;
|
|
3131
|
+
if (existing) {
|
|
3132
|
+
guardrails = yield* deserializeGuardrails(existing).pipe(
|
|
3133
|
+
Effect4.mapError(
|
|
3134
|
+
(err) => new GuardrailsStoreError({
|
|
3135
|
+
message: err.message,
|
|
3136
|
+
operation: "add",
|
|
3137
|
+
cause: err
|
|
3138
|
+
})
|
|
3139
|
+
)
|
|
3140
|
+
);
|
|
3141
|
+
} else {
|
|
3142
|
+
const now = yield* DateTime.now;
|
|
3143
|
+
guardrails = createEmptyGuardrails(sessionId, DateTime.formatIso(now));
|
|
3144
|
+
}
|
|
3145
|
+
const updatedGuardrails = {
|
|
3146
|
+
...guardrails,
|
|
3147
|
+
guardrails: [...guardrails.guardrails, guardrail]
|
|
3148
|
+
};
|
|
3149
|
+
yield* Effect4.tryPromise({
|
|
3150
|
+
try: () => writeFile(
|
|
3151
|
+
guardrailsPath,
|
|
3152
|
+
serializeGuardrails(updatedGuardrails),
|
|
3153
|
+
"utf-8"
|
|
3154
|
+
),
|
|
3155
|
+
catch: (error) => new GuardrailsStoreError({
|
|
3156
|
+
message: `Failed to write guardrails file: ${guardrailsPath}`,
|
|
3157
|
+
operation: "add",
|
|
3158
|
+
cause: error
|
|
3159
|
+
})
|
|
3160
|
+
});
|
|
3161
|
+
}),
|
|
3162
|
+
load: (sessionId) => Effect4.gen(function* () {
|
|
3163
|
+
const guardrailsPath = getGuardrailsPath(sessionId);
|
|
3164
|
+
const content = yield* Effect4.tryPromise({
|
|
3165
|
+
try: async () => {
|
|
3166
|
+
try {
|
|
3167
|
+
return await readFile(guardrailsPath, "utf-8");
|
|
3168
|
+
} catch {
|
|
3169
|
+
return null;
|
|
3170
|
+
}
|
|
3171
|
+
},
|
|
3172
|
+
catch: (error) => new GuardrailsStoreError({
|
|
3173
|
+
message: `Failed to read guardrails file: ${guardrailsPath}`,
|
|
3174
|
+
operation: "load",
|
|
3175
|
+
cause: error
|
|
3176
|
+
})
|
|
3177
|
+
});
|
|
3178
|
+
if (content === null) {
|
|
3179
|
+
const now = yield* DateTime.now;
|
|
3180
|
+
return createEmptyGuardrails(sessionId, DateTime.formatIso(now));
|
|
3181
|
+
}
|
|
3182
|
+
return yield* deserializeGuardrails(content);
|
|
3183
|
+
}),
|
|
3184
|
+
getActive: (sessionId) => Effect4.gen(function* () {
|
|
3185
|
+
const guardrails = yield* make.load(sessionId);
|
|
3186
|
+
return guardrails.guardrails;
|
|
3187
|
+
})
|
|
3188
|
+
};
|
|
3189
|
+
var Live = Layer.succeed(GuardrailsStore, make);
|
|
3190
|
+
var FileSystemGuardrails = {
|
|
3191
|
+
Live
|
|
3192
|
+
};
|
|
3193
|
+
|
|
3194
|
+
// src/layers/guardrails/memory.ts
|
|
3195
|
+
init_esm_shims();
|
|
3196
|
+
import { DateTime as DateTime2, Effect as Effect5, Layer as Layer2, Ref as Ref3 } from "effect";
|
|
3197
|
+
function createMemoryGuardrailsStore(stateRef) {
|
|
3198
|
+
return {
|
|
3199
|
+
add: (sessionId, guardrail) => Effect5.gen(function* () {
|
|
3200
|
+
const state = yield* Ref3.get(stateRef);
|
|
3201
|
+
let guardrails = state.get(sessionId);
|
|
3202
|
+
if (!guardrails) {
|
|
3203
|
+
const now = yield* DateTime2.now;
|
|
3204
|
+
guardrails = {
|
|
3205
|
+
sessionId,
|
|
3206
|
+
createdAt: DateTime2.formatIso(now),
|
|
3207
|
+
guardrails: []
|
|
3208
|
+
};
|
|
3209
|
+
}
|
|
3210
|
+
const updatedGuardrails = {
|
|
3211
|
+
...guardrails,
|
|
3212
|
+
guardrails: [...guardrails.guardrails, guardrail]
|
|
3213
|
+
};
|
|
3214
|
+
state.set(sessionId, updatedGuardrails);
|
|
3215
|
+
yield* Ref3.set(stateRef, state);
|
|
3216
|
+
}),
|
|
3217
|
+
load: (sessionId) => Effect5.gen(function* () {
|
|
3218
|
+
const state = yield* Ref3.get(stateRef);
|
|
3219
|
+
const guardrails = state.get(sessionId);
|
|
3220
|
+
if (!guardrails) {
|
|
3221
|
+
const now = yield* DateTime2.now;
|
|
3222
|
+
return {
|
|
3223
|
+
sessionId,
|
|
3224
|
+
createdAt: DateTime2.formatIso(now),
|
|
3225
|
+
guardrails: []
|
|
3226
|
+
};
|
|
3227
|
+
}
|
|
3228
|
+
return guardrails;
|
|
3229
|
+
}),
|
|
3230
|
+
getActive: (sessionId) => Effect5.gen(function* () {
|
|
3231
|
+
const state = yield* Ref3.get(stateRef);
|
|
3232
|
+
const guardrails = state.get(sessionId);
|
|
3233
|
+
if (!guardrails) {
|
|
3234
|
+
return [];
|
|
3235
|
+
}
|
|
3236
|
+
return guardrails.guardrails;
|
|
3237
|
+
})
|
|
3238
|
+
};
|
|
3239
|
+
}
|
|
3240
|
+
function layer() {
|
|
3241
|
+
return Layer2.effect(
|
|
3242
|
+
GuardrailsStore,
|
|
3243
|
+
Effect5.gen(function* () {
|
|
3244
|
+
const stateRef = yield* Ref3.make(/* @__PURE__ */ new Map());
|
|
3245
|
+
return createMemoryGuardrailsStore(stateRef);
|
|
3246
|
+
})
|
|
3247
|
+
);
|
|
3248
|
+
}
|
|
3249
|
+
var Live2 = layer();
|
|
3250
|
+
var MemoryGuardrails = {
|
|
3251
|
+
Live: Live2,
|
|
3252
|
+
layer
|
|
3253
|
+
};
|
|
3254
|
+
|
|
3255
|
+
// src/layers/llm/claude-cli.ts
|
|
3256
|
+
init_esm_shims();
|
|
3257
|
+
import { spawn } from "child_process";
|
|
3258
|
+
import { Effect as Effect7, Layer as Layer3, Stream as Stream5 } from "effect";
|
|
3259
|
+
|
|
3260
|
+
// src/services/llm.ts
|
|
3261
|
+
init_esm_shims();
|
|
3262
|
+
import { Context as Context2 } from "effect";
|
|
3263
|
+
var LLM = class extends Context2.Tag("@ferix/LLM")() {
|
|
3264
|
+
};
|
|
3265
|
+
|
|
3266
|
+
// src/layers/llm/stream.ts
|
|
3267
|
+
init_esm_shims();
|
|
3268
|
+
import { createInterface } from "readline";
|
|
3269
|
+
import { Effect as Effect6, Stream as Stream4 } from "effect";
|
|
3270
|
+
|
|
3271
|
+
// src/layers/llm/parsers.ts
|
|
3272
|
+
init_esm_shims();
|
|
3273
|
+
function parseJsonLine(line) {
|
|
3274
|
+
if (!line.startsWith("{")) {
|
|
3275
|
+
return null;
|
|
3276
|
+
}
|
|
3277
|
+
try {
|
|
3278
|
+
return JSON.parse(line);
|
|
3279
|
+
} catch {
|
|
3280
|
+
return null;
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
function isTextContent(json) {
|
|
3284
|
+
return typeof json === "object" && json !== null && "type" in json && typeof json.type === "string";
|
|
3285
|
+
}
|
|
3286
|
+
function isToolUse(json) {
|
|
3287
|
+
return typeof json === "object" && json !== null && "type" in json && "content_block" in json;
|
|
3288
|
+
}
|
|
3289
|
+
function extractText(json) {
|
|
3290
|
+
if (!isTextContent(json)) {
|
|
3291
|
+
return null;
|
|
3292
|
+
}
|
|
3293
|
+
if (json.type === "content_block_delta") {
|
|
3294
|
+
const delta = json;
|
|
3295
|
+
if (delta.delta?.type === "text_delta" && delta.delta.text) {
|
|
3296
|
+
return delta.delta.text;
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
if (json.type === "assistant" && json.message?.content) {
|
|
3300
|
+
for (const block of json.message.content) {
|
|
3301
|
+
if (block.type === "text" && block.text) {
|
|
3302
|
+
return block.text;
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
return null;
|
|
3307
|
+
}
|
|
3308
|
+
function isToolInputDelta(json) {
|
|
3309
|
+
return typeof json === "object" && json !== null && "type" in json && json.type === "content_block_delta" && "delta" in json;
|
|
3310
|
+
}
|
|
3311
|
+
function extractToolInfo(json) {
|
|
3312
|
+
if (typeof json === "object" && json !== null && "type" in json && json.type === "content_block_stop") {
|
|
3313
|
+
return {
|
|
3314
|
+
type: "end",
|
|
3315
|
+
name: "unknown"
|
|
3316
|
+
};
|
|
3317
|
+
}
|
|
3318
|
+
if (!isToolUse(json)) {
|
|
3319
|
+
if (isToolInputDelta(json) && json.delta?.type === "input_json_delta" && json.delta.partial_json) {
|
|
3320
|
+
return {
|
|
3321
|
+
type: "input_delta",
|
|
3322
|
+
name: "",
|
|
3323
|
+
partialJson: json.delta.partial_json
|
|
3324
|
+
};
|
|
3325
|
+
}
|
|
3326
|
+
return null;
|
|
3327
|
+
}
|
|
3328
|
+
if (json.type === "content_block_start" && json.content_block?.type === "tool_use") {
|
|
3329
|
+
return {
|
|
3330
|
+
type: "start",
|
|
3331
|
+
name: json.content_block.name || "unknown"
|
|
3332
|
+
};
|
|
3333
|
+
}
|
|
3334
|
+
return null;
|
|
3335
|
+
}
|
|
3336
|
+
function safeParseJson(jsonStr) {
|
|
3337
|
+
try {
|
|
3338
|
+
return JSON.parse(jsonStr);
|
|
3339
|
+
} catch {
|
|
3340
|
+
return null;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
function unwrapStreamEvent(json) {
|
|
3344
|
+
if (typeof json === "object" && json !== null && "type" in json && json.type === "stream_event" && "event" in json) {
|
|
3345
|
+
return json.event;
|
|
3346
|
+
}
|
|
3347
|
+
return json;
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
// src/layers/llm/stream.ts
|
|
3351
|
+
function handleToolEvent(toolInfo, toolState, emit) {
|
|
3352
|
+
if (toolInfo.type === "start") {
|
|
3353
|
+
toolState.currentTool = toolInfo.name;
|
|
3354
|
+
toolState.inputChunks.length = 0;
|
|
3355
|
+
emit.single({ _tag: "ToolStart", tool: toolInfo.name });
|
|
3356
|
+
return;
|
|
3357
|
+
}
|
|
3358
|
+
if (toolInfo.type === "input_delta" && toolInfo.partialJson) {
|
|
3359
|
+
toolState.inputChunks.push(toolInfo.partialJson);
|
|
3360
|
+
return;
|
|
3361
|
+
}
|
|
3362
|
+
if (toolInfo.type === "end" && toolState.currentTool) {
|
|
3363
|
+
const inputJson = toolState.inputChunks.join("");
|
|
3364
|
+
const input = safeParseJson(inputJson);
|
|
3365
|
+
if (input !== null) {
|
|
3366
|
+
emit.single({ _tag: "ToolUse", tool: toolState.currentTool, input });
|
|
3367
|
+
}
|
|
3368
|
+
emit.single({ _tag: "ToolEnd", tool: toolState.currentTool });
|
|
3369
|
+
toolState.currentTool = "";
|
|
3370
|
+
toolState.inputChunks.length = 0;
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
function processJsonLine(json, outputChunks, toolState, emit) {
|
|
3374
|
+
const event = unwrapStreamEvent(json);
|
|
3375
|
+
const text = extractText(event);
|
|
3376
|
+
if (text) {
|
|
3377
|
+
outputChunks.push(text);
|
|
3378
|
+
emit.single({ _tag: "Text", text });
|
|
3379
|
+
return;
|
|
3380
|
+
}
|
|
3381
|
+
const toolInfo = extractToolInfo(event);
|
|
3382
|
+
if (toolInfo) {
|
|
3383
|
+
handleToolEvent(toolInfo, toolState, emit);
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
function createEventStream(child) {
|
|
3387
|
+
return Stream4.async((emit) => {
|
|
3388
|
+
const outputChunks = [];
|
|
3389
|
+
const toolState = { currentTool: "", inputChunks: [] };
|
|
3390
|
+
const stdout = child.stdout;
|
|
3391
|
+
if (!stdout) {
|
|
3392
|
+
emit.fail(
|
|
3393
|
+
new LLMError({ message: "Failed to get stdout from child process" })
|
|
3394
|
+
);
|
|
3395
|
+
return Effect6.void;
|
|
3396
|
+
}
|
|
3397
|
+
const rl = createInterface({
|
|
3398
|
+
input: stdout,
|
|
3399
|
+
crlfDelay: Number.POSITIVE_INFINITY
|
|
3400
|
+
});
|
|
3401
|
+
rl.on("line", (line) => {
|
|
3402
|
+
const json = parseJsonLine(line);
|
|
3403
|
+
if (json) {
|
|
3404
|
+
processJsonLine(json, outputChunks, toolState, emit);
|
|
3405
|
+
}
|
|
3406
|
+
});
|
|
3407
|
+
child.stderr?.on("data", (data) => {
|
|
3408
|
+
const text = data.toString().trim();
|
|
3409
|
+
if (text) {
|
|
3410
|
+
emit.single({ _tag: "Text", text: `[stderr] ${text}` });
|
|
3411
|
+
}
|
|
3412
|
+
});
|
|
3413
|
+
child.on("close", (exitCode) => {
|
|
3414
|
+
if (exitCode !== 0) {
|
|
3415
|
+
emit.fail(
|
|
3416
|
+
new LLMError({
|
|
3417
|
+
message: `Claude CLI exited with code ${exitCode}`
|
|
3418
|
+
})
|
|
3419
|
+
);
|
|
3420
|
+
} else {
|
|
3421
|
+
const fullOutput = outputChunks.join("");
|
|
3422
|
+
emit.single({ _tag: "Done", output: fullOutput });
|
|
3423
|
+
emit.end();
|
|
3424
|
+
}
|
|
3425
|
+
});
|
|
3426
|
+
child.on("error", (error) => {
|
|
3427
|
+
emit.fail(
|
|
3428
|
+
new LLMError({
|
|
3429
|
+
message: error.message,
|
|
3430
|
+
cause: error
|
|
3431
|
+
})
|
|
3432
|
+
);
|
|
3433
|
+
});
|
|
3434
|
+
return Effect6.sync(() => {
|
|
3435
|
+
child.kill("SIGTERM");
|
|
3436
|
+
});
|
|
3437
|
+
});
|
|
3438
|
+
}
|
|
3439
|
+
|
|
3440
|
+
// src/layers/llm/claude-cli.ts
|
|
3441
|
+
var make2 = {
|
|
3442
|
+
execute: (prompt) => {
|
|
3443
|
+
return Stream5.unwrap(
|
|
3444
|
+
Effect7.sync(() => {
|
|
3445
|
+
const child = spawn(
|
|
3446
|
+
"claude",
|
|
3447
|
+
[
|
|
3448
|
+
"--permission-mode",
|
|
3449
|
+
"acceptEdits",
|
|
3450
|
+
"--output-format",
|
|
3451
|
+
"stream-json",
|
|
3452
|
+
"--verbose",
|
|
3453
|
+
"--include-partial-messages",
|
|
3454
|
+
"-p",
|
|
3455
|
+
prompt
|
|
3456
|
+
],
|
|
3457
|
+
{
|
|
3458
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
3459
|
+
env: {
|
|
3460
|
+
...process.env,
|
|
3461
|
+
FORCE_COLOR: "1"
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
);
|
|
3465
|
+
return createEventStream(child);
|
|
3466
|
+
})
|
|
3467
|
+
);
|
|
3468
|
+
}
|
|
3469
|
+
};
|
|
3470
|
+
var Live3 = Layer3.succeed(LLM, make2);
|
|
3471
|
+
var ClaudeCLI = {
|
|
3472
|
+
Live: Live3
|
|
3473
|
+
};
|
|
3474
|
+
|
|
3475
|
+
// src/layers/llm/mock.ts
|
|
3476
|
+
init_esm_shims();
|
|
3477
|
+
import { Effect as Effect8, Layer as Layer4, Schema as S14, Stream as Stream6 } from "effect";
|
|
3478
|
+
var MockLLMConfigSchema = S14.Struct({
|
|
3479
|
+
events: S14.Array(LLMEventSchema),
|
|
3480
|
+
delayMs: S14.optional(S14.Number)
|
|
3190
3481
|
});
|
|
3482
|
+
function createMockLLM(config) {
|
|
3483
|
+
return {
|
|
3484
|
+
execute: (_prompt) => {
|
|
3485
|
+
const baseStream = Stream6.fromIterable(config.events);
|
|
3486
|
+
if (config.delayMs !== void 0 && config.delayMs > 0) {
|
|
3487
|
+
const delay = config.delayMs;
|
|
3488
|
+
return baseStream.pipe(Stream6.tap(() => Effect8.sleep(delay)));
|
|
3489
|
+
}
|
|
3490
|
+
return baseStream;
|
|
3491
|
+
}
|
|
3492
|
+
};
|
|
3493
|
+
}
|
|
3494
|
+
var defaultMockEvents = [
|
|
3495
|
+
{ _tag: "Text", text: "Processing task...\n" },
|
|
3496
|
+
{ _tag: "ToolStart", tool: "Read" },
|
|
3497
|
+
{ _tag: "ToolEnd", tool: "Read" },
|
|
3498
|
+
{ _tag: "Text", text: "Task completed successfully.\n" },
|
|
3499
|
+
{
|
|
3500
|
+
_tag: "Done",
|
|
3501
|
+
output: "Processing task...\nTask completed successfully.\n"
|
|
3502
|
+
}
|
|
3503
|
+
];
|
|
3504
|
+
var defaultMock = createMockLLM({ events: defaultMockEvents });
|
|
3505
|
+
var Live4 = Layer4.succeed(LLM, defaultMock);
|
|
3506
|
+
function layer2(config) {
|
|
3507
|
+
return Layer4.succeed(LLM, createMockLLM(config));
|
|
3508
|
+
}
|
|
3509
|
+
var Mock = {
|
|
3510
|
+
Live: Live4,
|
|
3511
|
+
layer: layer2,
|
|
3512
|
+
createMockLLM
|
|
3513
|
+
};
|
|
3514
|
+
|
|
3515
|
+
// src/layers/plan/file-system.ts
|
|
3516
|
+
init_esm_shims();
|
|
3517
|
+
import { access, mkdir as mkdir2, readdir, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
3518
|
+
import { join as join2 } from "path";
|
|
3519
|
+
import { Effect as Effect9, Layer as Layer5 } from "effect";
|
|
3191
3520
|
|
|
3192
3521
|
// src/services/plan-store.ts
|
|
3193
3522
|
init_esm_shims();
|
|
3194
|
-
import { Context as
|
|
3195
|
-
var PlanStore = class extends
|
|
3523
|
+
import { Context as Context3 } from "effect";
|
|
3524
|
+
var PlanStore = class extends Context3.Tag("@ferix/PlanStore")() {
|
|
3196
3525
|
};
|
|
3197
3526
|
|
|
3198
3527
|
// src/layers/plan/file-system.ts
|
|
3199
|
-
var
|
|
3200
|
-
function
|
|
3201
|
-
return
|
|
3202
|
-
try: () =>
|
|
3528
|
+
var PLANS_DIR2 = ".ferix/plans";
|
|
3529
|
+
function ensureDir2(dirPath) {
|
|
3530
|
+
return Effect9.tryPromise({
|
|
3531
|
+
try: () => mkdir2(dirPath, { recursive: true }),
|
|
3203
3532
|
catch: (error) => new PlanStoreError({
|
|
3204
3533
|
message: `Failed to create directory: ${dirPath}`,
|
|
3205
3534
|
operation: "create",
|
|
3206
3535
|
cause: error
|
|
3207
3536
|
})
|
|
3208
|
-
}).pipe(
|
|
3537
|
+
}).pipe(Effect9.asVoid);
|
|
3209
3538
|
}
|
|
3210
|
-
function
|
|
3211
|
-
return
|
|
3539
|
+
function getSessionDir2(sessionId) {
|
|
3540
|
+
return join2(process.cwd(), PLANS_DIR2, sessionId);
|
|
3212
3541
|
}
|
|
3213
3542
|
function getPlanPath(sessionId, planId) {
|
|
3214
|
-
return
|
|
3543
|
+
return join2(getSessionDir2(sessionId), `${planId}.json`);
|
|
3215
3544
|
}
|
|
3216
3545
|
function generatePlanId(taskNumber) {
|
|
3217
3546
|
return PlanId(`task-${taskNumber}`);
|
|
@@ -3220,8 +3549,8 @@ function serializePlan(plan) {
|
|
|
3220
3549
|
return JSON.stringify(plan, null, 2);
|
|
3221
3550
|
}
|
|
3222
3551
|
function deserializePlan(json, planId) {
|
|
3223
|
-
return
|
|
3224
|
-
const parsed = yield*
|
|
3552
|
+
return Effect9.gen(function* () {
|
|
3553
|
+
const parsed = yield* Effect9.try({
|
|
3225
3554
|
try: () => JSON.parse(json),
|
|
3226
3555
|
catch: (error) => new PlanStoreError({
|
|
3227
3556
|
message: `Invalid JSON in plan file: ${String(error)}`,
|
|
@@ -3230,7 +3559,7 @@ function deserializePlan(json, planId) {
|
|
|
3230
3559
|
})
|
|
3231
3560
|
});
|
|
3232
3561
|
const validated = yield* decodePlanData(parsed).pipe(
|
|
3233
|
-
|
|
3562
|
+
Effect9.mapError(
|
|
3234
3563
|
(error) => new PlanStoreError({
|
|
3235
3564
|
message: `Plan validation failed: ${String(error)}`,
|
|
3236
3565
|
operation: "load",
|
|
@@ -3244,11 +3573,11 @@ function deserializePlan(json, planId) {
|
|
|
3244
3573
|
};
|
|
3245
3574
|
});
|
|
3246
3575
|
}
|
|
3247
|
-
var
|
|
3248
|
-
create: (sessionId, plan) =>
|
|
3249
|
-
const sessionDir =
|
|
3250
|
-
yield*
|
|
3251
|
-
const existingPlans = yield*
|
|
3576
|
+
var make3 = {
|
|
3577
|
+
create: (sessionId, plan) => Effect9.gen(function* () {
|
|
3578
|
+
const sessionDir = getSessionDir2(sessionId);
|
|
3579
|
+
yield* ensureDir2(sessionDir);
|
|
3580
|
+
const existingPlans = yield* Effect9.tryPromise({
|
|
3252
3581
|
try: async () => {
|
|
3253
3582
|
try {
|
|
3254
3583
|
const files = await readdir(sessionDir);
|
|
@@ -3265,8 +3594,8 @@ var make2 = {
|
|
|
3265
3594
|
const planId = generatePlanId(existingPlans + 1);
|
|
3266
3595
|
const planPath = getPlanPath(sessionId, planId);
|
|
3267
3596
|
const fullPlan = { ...plan, id: planId };
|
|
3268
|
-
yield*
|
|
3269
|
-
try: () =>
|
|
3597
|
+
yield* Effect9.tryPromise({
|
|
3598
|
+
try: () => writeFile2(planPath, serializePlan(fullPlan), "utf-8"),
|
|
3270
3599
|
catch: (error) => new PlanStoreError({
|
|
3271
3600
|
message: `Failed to write plan file: ${planPath}`,
|
|
3272
3601
|
operation: "create",
|
|
@@ -3275,11 +3604,11 @@ var make2 = {
|
|
|
3275
3604
|
});
|
|
3276
3605
|
return planId;
|
|
3277
3606
|
}),
|
|
3278
|
-
load: (planId, sessionId) =>
|
|
3607
|
+
load: (planId, sessionId) => Effect9.gen(function* () {
|
|
3279
3608
|
if (sessionId) {
|
|
3280
3609
|
const planPath = getPlanPath(sessionId, planId);
|
|
3281
|
-
const content = yield*
|
|
3282
|
-
try: () =>
|
|
3610
|
+
const content = yield* Effect9.tryPromise({
|
|
3611
|
+
try: () => readFile2(planPath, "utf-8"),
|
|
3283
3612
|
catch: (error) => new PlanStoreError({
|
|
3284
3613
|
message: `Failed to read plan file: ${planPath}`,
|
|
3285
3614
|
operation: "load",
|
|
@@ -3288,9 +3617,9 @@ var make2 = {
|
|
|
3288
3617
|
});
|
|
3289
3618
|
return yield* deserializePlan(content, planId);
|
|
3290
3619
|
}
|
|
3291
|
-
const sessionDirs = yield*
|
|
3620
|
+
const sessionDirs = yield* Effect9.tryPromise({
|
|
3292
3621
|
try: async () => {
|
|
3293
|
-
const plansDir =
|
|
3622
|
+
const plansDir = join2(process.cwd(), PLANS_DIR2);
|
|
3294
3623
|
const dirs = await readdir(plansDir);
|
|
3295
3624
|
return dirs;
|
|
3296
3625
|
},
|
|
@@ -3302,7 +3631,7 @@ var make2 = {
|
|
|
3302
3631
|
});
|
|
3303
3632
|
for (const sid of sessionDirs) {
|
|
3304
3633
|
const planPath = getPlanPath(sid, planId);
|
|
3305
|
-
const exists = yield*
|
|
3634
|
+
const exists = yield* Effect9.tryPromise({
|
|
3306
3635
|
try: async () => {
|
|
3307
3636
|
await access(planPath);
|
|
3308
3637
|
return true;
|
|
@@ -3311,10 +3640,10 @@ var make2 = {
|
|
|
3311
3640
|
message: "File not found",
|
|
3312
3641
|
operation: "load"
|
|
3313
3642
|
})
|
|
3314
|
-
}).pipe(
|
|
3643
|
+
}).pipe(Effect9.orElseSucceed(() => false));
|
|
3315
3644
|
if (exists) {
|
|
3316
|
-
const content = yield*
|
|
3317
|
-
try: () =>
|
|
3645
|
+
const content = yield* Effect9.tryPromise({
|
|
3646
|
+
try: () => readFile2(planPath, "utf-8"),
|
|
3318
3647
|
catch: (error) => new PlanStoreError({
|
|
3319
3648
|
message: `Failed to read plan file: ${planPath}`,
|
|
3320
3649
|
operation: "load",
|
|
@@ -3324,17 +3653,17 @@ var make2 = {
|
|
|
3324
3653
|
return yield* deserializePlan(content, planId);
|
|
3325
3654
|
}
|
|
3326
3655
|
}
|
|
3327
|
-
return yield*
|
|
3656
|
+
return yield* Effect9.fail(
|
|
3328
3657
|
new PlanStoreError({
|
|
3329
3658
|
message: `Plan not found: ${planId}`,
|
|
3330
3659
|
operation: "load"
|
|
3331
3660
|
})
|
|
3332
3661
|
);
|
|
3333
3662
|
}),
|
|
3334
|
-
update: (planId, plan) =>
|
|
3663
|
+
update: (planId, plan) => Effect9.gen(function* () {
|
|
3335
3664
|
const planPath = getPlanPath(plan.sessionId, planId);
|
|
3336
|
-
yield*
|
|
3337
|
-
try: () =>
|
|
3665
|
+
yield* Effect9.tryPromise({
|
|
3666
|
+
try: () => writeFile2(planPath, serializePlan(plan), "utf-8"),
|
|
3338
3667
|
catch: (error) => new PlanStoreError({
|
|
3339
3668
|
message: `Failed to update plan file: ${planPath}`,
|
|
3340
3669
|
operation: "update",
|
|
@@ -3342,9 +3671,9 @@ var make2 = {
|
|
|
3342
3671
|
})
|
|
3343
3672
|
});
|
|
3344
3673
|
}),
|
|
3345
|
-
list: (sessionId) =>
|
|
3346
|
-
const sessionDir =
|
|
3347
|
-
const files = yield*
|
|
3674
|
+
list: (sessionId) => Effect9.gen(function* () {
|
|
3675
|
+
const sessionDir = getSessionDir2(sessionId);
|
|
3676
|
+
const files = yield* Effect9.tryPromise({
|
|
3348
3677
|
try: async () => {
|
|
3349
3678
|
try {
|
|
3350
3679
|
return await readdir(sessionDir);
|
|
@@ -3361,18 +3690,18 @@ var make2 = {
|
|
|
3361
3690
|
return files.filter((f) => f.endsWith(".json")).map((f) => PlanId(f.replace(".json", "")));
|
|
3362
3691
|
})
|
|
3363
3692
|
};
|
|
3364
|
-
var
|
|
3693
|
+
var Live5 = Layer5.succeed(PlanStore, make3);
|
|
3365
3694
|
var FileSystemPlan = {
|
|
3366
|
-
Live:
|
|
3695
|
+
Live: Live5
|
|
3367
3696
|
};
|
|
3368
3697
|
|
|
3369
3698
|
// src/layers/plan/memory.ts
|
|
3370
3699
|
init_esm_shims();
|
|
3371
|
-
import { Effect as
|
|
3700
|
+
import { Effect as Effect10, Layer as Layer6, Ref as Ref4 } from "effect";
|
|
3372
3701
|
function createMemoryPlanStore(stateRef) {
|
|
3373
3702
|
return {
|
|
3374
|
-
create: (sessionId, plan) =>
|
|
3375
|
-
const state = yield*
|
|
3703
|
+
create: (sessionId, plan) => Effect10.gen(function* () {
|
|
3704
|
+
const state = yield* Ref4.get(stateRef);
|
|
3376
3705
|
if (!state.has(sessionId)) {
|
|
3377
3706
|
state.set(sessionId, /* @__PURE__ */ new Map());
|
|
3378
3707
|
}
|
|
@@ -3383,18 +3712,18 @@ function createMemoryPlanStore(stateRef) {
|
|
|
3383
3712
|
const planId = PlanId(`task-${sessionPlans.size + 1}`);
|
|
3384
3713
|
const fullPlan = { ...plan, id: planId };
|
|
3385
3714
|
sessionPlans.set(planId, fullPlan);
|
|
3386
|
-
yield*
|
|
3715
|
+
yield* Ref4.set(stateRef, state);
|
|
3387
3716
|
return planId;
|
|
3388
3717
|
}),
|
|
3389
|
-
load: (planId, sessionId) =>
|
|
3390
|
-
const state = yield*
|
|
3718
|
+
load: (planId, sessionId) => Effect10.gen(function* () {
|
|
3719
|
+
const state = yield* Ref4.get(stateRef);
|
|
3391
3720
|
if (sessionId) {
|
|
3392
3721
|
const sessionPlans = state.get(sessionId);
|
|
3393
3722
|
const plan = sessionPlans?.get(planId);
|
|
3394
3723
|
if (plan) {
|
|
3395
3724
|
return plan;
|
|
3396
3725
|
}
|
|
3397
|
-
return yield*
|
|
3726
|
+
return yield* Effect10.fail(
|
|
3398
3727
|
new PlanStoreError({
|
|
3399
3728
|
message: `Plan not found: ${planId}`,
|
|
3400
3729
|
operation: "load"
|
|
@@ -3407,18 +3736,18 @@ function createMemoryPlanStore(stateRef) {
|
|
|
3407
3736
|
return plan;
|
|
3408
3737
|
}
|
|
3409
3738
|
}
|
|
3410
|
-
return yield*
|
|
3739
|
+
return yield* Effect10.fail(
|
|
3411
3740
|
new PlanStoreError({
|
|
3412
3741
|
message: `Plan not found: ${planId}`,
|
|
3413
3742
|
operation: "load"
|
|
3414
3743
|
})
|
|
3415
3744
|
);
|
|
3416
3745
|
}),
|
|
3417
|
-
update: (planId, plan) =>
|
|
3418
|
-
const state = yield*
|
|
3746
|
+
update: (planId, plan) => Effect10.gen(function* () {
|
|
3747
|
+
const state = yield* Ref4.get(stateRef);
|
|
3419
3748
|
const sessionPlans = state.get(plan.sessionId);
|
|
3420
3749
|
if (!sessionPlans) {
|
|
3421
|
-
return yield*
|
|
3750
|
+
return yield* Effect10.fail(
|
|
3422
3751
|
new PlanStoreError({
|
|
3423
3752
|
message: `Session not found: ${plan.sessionId}`,
|
|
3424
3753
|
operation: "update"
|
|
@@ -3426,10 +3755,10 @@ function createMemoryPlanStore(stateRef) {
|
|
|
3426
3755
|
);
|
|
3427
3756
|
}
|
|
3428
3757
|
sessionPlans.set(planId, plan);
|
|
3429
|
-
yield*
|
|
3758
|
+
yield* Ref4.set(stateRef, state);
|
|
3430
3759
|
}),
|
|
3431
|
-
list: (sessionId) =>
|
|
3432
|
-
const state = yield*
|
|
3760
|
+
list: (sessionId) => Effect10.gen(function* () {
|
|
3761
|
+
const state = yield* Ref4.get(stateRef);
|
|
3433
3762
|
const sessionPlans = state.get(sessionId);
|
|
3434
3763
|
if (!sessionPlans) {
|
|
3435
3764
|
return [];
|
|
@@ -3438,32 +3767,236 @@ function createMemoryPlanStore(stateRef) {
|
|
|
3438
3767
|
})
|
|
3439
3768
|
};
|
|
3440
3769
|
}
|
|
3441
|
-
function
|
|
3442
|
-
return
|
|
3770
|
+
function layer3() {
|
|
3771
|
+
return Layer6.effect(
|
|
3443
3772
|
PlanStore,
|
|
3444
|
-
|
|
3445
|
-
const stateRef = yield*
|
|
3773
|
+
Effect10.gen(function* () {
|
|
3774
|
+
const stateRef = yield* Ref4.make(/* @__PURE__ */ new Map());
|
|
3446
3775
|
return createMemoryPlanStore(stateRef);
|
|
3447
3776
|
})
|
|
3448
3777
|
);
|
|
3449
3778
|
}
|
|
3450
|
-
var
|
|
3779
|
+
var Live6 = layer3();
|
|
3451
3780
|
var MemoryPlan = {
|
|
3452
|
-
Live:
|
|
3453
|
-
layer:
|
|
3781
|
+
Live: Live6,
|
|
3782
|
+
layer: layer3
|
|
3783
|
+
};
|
|
3784
|
+
|
|
3785
|
+
// src/layers/progress/file-system.ts
|
|
3786
|
+
init_esm_shims();
|
|
3787
|
+
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
3788
|
+
import { join as join3 } from "path";
|
|
3789
|
+
import { DateTime as DateTime3, Effect as Effect11, Layer as Layer7 } from "effect";
|
|
3790
|
+
|
|
3791
|
+
// src/services/progress-store.ts
|
|
3792
|
+
init_esm_shims();
|
|
3793
|
+
import { Context as Context4 } from "effect";
|
|
3794
|
+
var ProgressStore = class extends Context4.Tag("@ferix/ProgressStore")() {
|
|
3795
|
+
};
|
|
3796
|
+
|
|
3797
|
+
// src/layers/progress/file-system.ts
|
|
3798
|
+
var PLANS_DIR3 = ".ferix/plans";
|
|
3799
|
+
function ensureDir3(dirPath) {
|
|
3800
|
+
return Effect11.tryPromise({
|
|
3801
|
+
try: () => mkdir3(dirPath, { recursive: true }),
|
|
3802
|
+
catch: (error) => new ProgressStoreError({
|
|
3803
|
+
message: `Failed to create directory: ${dirPath}`,
|
|
3804
|
+
operation: "append",
|
|
3805
|
+
cause: error
|
|
3806
|
+
})
|
|
3807
|
+
}).pipe(Effect11.asVoid);
|
|
3808
|
+
}
|
|
3809
|
+
function getSessionDir3(sessionId) {
|
|
3810
|
+
return join3(process.cwd(), PLANS_DIR3, sessionId);
|
|
3811
|
+
}
|
|
3812
|
+
function getProgressPath(sessionId) {
|
|
3813
|
+
return join3(getSessionDir3(sessionId), "progress.json");
|
|
3814
|
+
}
|
|
3815
|
+
function serializeProgress(progress) {
|
|
3816
|
+
return JSON.stringify(progress, null, 2);
|
|
3817
|
+
}
|
|
3818
|
+
function deserializeProgress(json) {
|
|
3819
|
+
return Effect11.gen(function* () {
|
|
3820
|
+
const parsed = yield* Effect11.try({
|
|
3821
|
+
try: () => JSON.parse(json),
|
|
3822
|
+
catch: (error) => new ProgressStoreError({
|
|
3823
|
+
message: `Invalid JSON in progress file: ${String(error)}`,
|
|
3824
|
+
operation: "load",
|
|
3825
|
+
cause: error
|
|
3826
|
+
})
|
|
3827
|
+
});
|
|
3828
|
+
const validated = yield* decodeProgressFile(parsed).pipe(
|
|
3829
|
+
Effect11.mapError(
|
|
3830
|
+
(error) => new ProgressStoreError({
|
|
3831
|
+
message: `Progress validation failed: ${String(error)}`,
|
|
3832
|
+
operation: "load",
|
|
3833
|
+
cause: error
|
|
3834
|
+
})
|
|
3835
|
+
)
|
|
3836
|
+
);
|
|
3837
|
+
return validated;
|
|
3838
|
+
});
|
|
3839
|
+
}
|
|
3840
|
+
function createEmptyProgress(sessionId, createdAt) {
|
|
3841
|
+
return {
|
|
3842
|
+
sessionId,
|
|
3843
|
+
createdAt,
|
|
3844
|
+
entries: []
|
|
3845
|
+
};
|
|
3846
|
+
}
|
|
3847
|
+
var make4 = {
|
|
3848
|
+
append: (sessionId, entry) => Effect11.gen(function* () {
|
|
3849
|
+
const sessionDir = getSessionDir3(sessionId);
|
|
3850
|
+
yield* ensureDir3(sessionDir);
|
|
3851
|
+
const progressPath = getProgressPath(sessionId);
|
|
3852
|
+
const existing = yield* Effect11.tryPromise({
|
|
3853
|
+
try: async () => {
|
|
3854
|
+
try {
|
|
3855
|
+
const content = await readFile3(progressPath, "utf-8");
|
|
3856
|
+
return content;
|
|
3857
|
+
} catch {
|
|
3858
|
+
return null;
|
|
3859
|
+
}
|
|
3860
|
+
},
|
|
3861
|
+
catch: (error) => new ProgressStoreError({
|
|
3862
|
+
message: `Failed to read progress file: ${progressPath}`,
|
|
3863
|
+
operation: "append",
|
|
3864
|
+
cause: error
|
|
3865
|
+
})
|
|
3866
|
+
});
|
|
3867
|
+
let progress;
|
|
3868
|
+
if (existing) {
|
|
3869
|
+
progress = yield* deserializeProgress(existing).pipe(
|
|
3870
|
+
Effect11.mapError(
|
|
3871
|
+
(err) => new ProgressStoreError({
|
|
3872
|
+
message: err.message,
|
|
3873
|
+
operation: "append",
|
|
3874
|
+
cause: err
|
|
3875
|
+
})
|
|
3876
|
+
)
|
|
3877
|
+
);
|
|
3878
|
+
} else {
|
|
3879
|
+
const now = yield* DateTime3.now;
|
|
3880
|
+
progress = createEmptyProgress(sessionId, DateTime3.formatIso(now));
|
|
3881
|
+
}
|
|
3882
|
+
const updatedProgress = {
|
|
3883
|
+
...progress,
|
|
3884
|
+
entries: [...progress.entries, entry]
|
|
3885
|
+
};
|
|
3886
|
+
yield* Effect11.tryPromise({
|
|
3887
|
+
try: () => writeFile3(progressPath, serializeProgress(updatedProgress), "utf-8"),
|
|
3888
|
+
catch: (error) => new ProgressStoreError({
|
|
3889
|
+
message: `Failed to write progress file: ${progressPath}`,
|
|
3890
|
+
operation: "append",
|
|
3891
|
+
cause: error
|
|
3892
|
+
})
|
|
3893
|
+
});
|
|
3894
|
+
}),
|
|
3895
|
+
load: (sessionId) => Effect11.gen(function* () {
|
|
3896
|
+
const progressPath = getProgressPath(sessionId);
|
|
3897
|
+
const content = yield* Effect11.tryPromise({
|
|
3898
|
+
try: async () => {
|
|
3899
|
+
try {
|
|
3900
|
+
return await readFile3(progressPath, "utf-8");
|
|
3901
|
+
} catch {
|
|
3902
|
+
return null;
|
|
3903
|
+
}
|
|
3904
|
+
},
|
|
3905
|
+
catch: (error) => new ProgressStoreError({
|
|
3906
|
+
message: `Failed to read progress file: ${progressPath}`,
|
|
3907
|
+
operation: "load",
|
|
3908
|
+
cause: error
|
|
3909
|
+
})
|
|
3910
|
+
});
|
|
3911
|
+
if (content === null) {
|
|
3912
|
+
const now = yield* DateTime3.now;
|
|
3913
|
+
return createEmptyProgress(sessionId, DateTime3.formatIso(now));
|
|
3914
|
+
}
|
|
3915
|
+
return yield* deserializeProgress(content);
|
|
3916
|
+
}),
|
|
3917
|
+
getRecent: (sessionId, count) => Effect11.gen(function* () {
|
|
3918
|
+
const progress = yield* make4.load(sessionId);
|
|
3919
|
+
const entries = progress.entries;
|
|
3920
|
+
return entries.slice(-count);
|
|
3921
|
+
})
|
|
3922
|
+
};
|
|
3923
|
+
var Live7 = Layer7.succeed(ProgressStore, make4);
|
|
3924
|
+
var FileSystemProgress = {
|
|
3925
|
+
Live: Live7
|
|
3926
|
+
};
|
|
3927
|
+
|
|
3928
|
+
// src/layers/progress/memory.ts
|
|
3929
|
+
init_esm_shims();
|
|
3930
|
+
import { DateTime as DateTime4, Effect as Effect12, Layer as Layer8, Ref as Ref5 } from "effect";
|
|
3931
|
+
function createMemoryProgressStore(stateRef) {
|
|
3932
|
+
return {
|
|
3933
|
+
append: (sessionId, entry) => Effect12.gen(function* () {
|
|
3934
|
+
const state = yield* Ref5.get(stateRef);
|
|
3935
|
+
let progress = state.get(sessionId);
|
|
3936
|
+
if (!progress) {
|
|
3937
|
+
const now = yield* DateTime4.now;
|
|
3938
|
+
progress = {
|
|
3939
|
+
sessionId,
|
|
3940
|
+
createdAt: DateTime4.formatIso(now),
|
|
3941
|
+
entries: []
|
|
3942
|
+
};
|
|
3943
|
+
}
|
|
3944
|
+
const updatedProgress = {
|
|
3945
|
+
...progress,
|
|
3946
|
+
entries: [...progress.entries, entry]
|
|
3947
|
+
};
|
|
3948
|
+
state.set(sessionId, updatedProgress);
|
|
3949
|
+
yield* Ref5.set(stateRef, state);
|
|
3950
|
+
}),
|
|
3951
|
+
load: (sessionId) => Effect12.gen(function* () {
|
|
3952
|
+
const state = yield* Ref5.get(stateRef);
|
|
3953
|
+
const progress = state.get(sessionId);
|
|
3954
|
+
if (!progress) {
|
|
3955
|
+
const now = yield* DateTime4.now;
|
|
3956
|
+
return {
|
|
3957
|
+
sessionId,
|
|
3958
|
+
createdAt: DateTime4.formatIso(now),
|
|
3959
|
+
entries: []
|
|
3960
|
+
};
|
|
3961
|
+
}
|
|
3962
|
+
return progress;
|
|
3963
|
+
}),
|
|
3964
|
+
getRecent: (sessionId, count) => Effect12.gen(function* () {
|
|
3965
|
+
const state = yield* Ref5.get(stateRef);
|
|
3966
|
+
const progress = state.get(sessionId);
|
|
3967
|
+
if (!progress) {
|
|
3968
|
+
return [];
|
|
3969
|
+
}
|
|
3970
|
+
return progress.entries.slice(-count);
|
|
3971
|
+
})
|
|
3972
|
+
};
|
|
3973
|
+
}
|
|
3974
|
+
function layer4() {
|
|
3975
|
+
return Layer8.effect(
|
|
3976
|
+
ProgressStore,
|
|
3977
|
+
Effect12.gen(function* () {
|
|
3978
|
+
const stateRef = yield* Ref5.make(/* @__PURE__ */ new Map());
|
|
3979
|
+
return createMemoryProgressStore(stateRef);
|
|
3980
|
+
})
|
|
3981
|
+
);
|
|
3982
|
+
}
|
|
3983
|
+
var Live8 = layer4();
|
|
3984
|
+
var MemoryProgress = {
|
|
3985
|
+
Live: Live8,
|
|
3986
|
+
layer: layer4
|
|
3454
3987
|
};
|
|
3455
3988
|
|
|
3456
3989
|
// src/layers/session/file-system.ts
|
|
3457
3990
|
init_esm_shims();
|
|
3458
|
-
import { mkdir as
|
|
3459
|
-
import { join as
|
|
3460
|
-
import { DateTime, Effect as
|
|
3991
|
+
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
3992
|
+
import { join as join4 } from "path";
|
|
3993
|
+
import { DateTime as DateTime5, Effect as Effect13, Layer as Layer9 } from "effect";
|
|
3461
3994
|
import { humanId } from "human-id";
|
|
3462
3995
|
|
|
3463
3996
|
// src/services/session-store.ts
|
|
3464
3997
|
init_esm_shims();
|
|
3465
|
-
import { Context as
|
|
3466
|
-
var SessionStore = class extends
|
|
3998
|
+
import { Context as Context5 } from "effect";
|
|
3999
|
+
var SessionStore = class extends Context5.Tag("@ferix/SessionStore")() {
|
|
3467
4000
|
};
|
|
3468
4001
|
|
|
3469
4002
|
// src/layers/session/file-system.ts
|
|
@@ -3472,25 +4005,25 @@ function generateSessionId(timestampMs) {
|
|
|
3472
4005
|
const id = humanId({ separator: "-", capitalize: false });
|
|
3473
4006
|
return `${id}-${timestampMs}`;
|
|
3474
4007
|
}
|
|
3475
|
-
function
|
|
3476
|
-
return
|
|
3477
|
-
try: () =>
|
|
4008
|
+
function ensureDir4(dirPath) {
|
|
4009
|
+
return Effect13.tryPromise({
|
|
4010
|
+
try: () => mkdir4(dirPath, { recursive: true }),
|
|
3478
4011
|
catch: (error) => new SessionStoreError({
|
|
3479
4012
|
message: `Failed to create directory: ${dirPath}`,
|
|
3480
4013
|
operation: "create",
|
|
3481
4014
|
cause: error
|
|
3482
4015
|
})
|
|
3483
|
-
}).pipe(
|
|
4016
|
+
}).pipe(Effect13.asVoid);
|
|
3484
4017
|
}
|
|
3485
4018
|
function getSessionPath(sessionId) {
|
|
3486
|
-
return
|
|
4019
|
+
return join4(process.cwd(), SESSIONS_DIR, `${sessionId}.json`);
|
|
3487
4020
|
}
|
|
3488
4021
|
function serializeSession(session) {
|
|
3489
4022
|
return JSON.stringify(session, null, 2);
|
|
3490
4023
|
}
|
|
3491
4024
|
function deserializeSession(json) {
|
|
3492
|
-
return
|
|
3493
|
-
const parsed = yield*
|
|
4025
|
+
return Effect13.gen(function* () {
|
|
4026
|
+
const parsed = yield* Effect13.try({
|
|
3494
4027
|
try: () => JSON.parse(json),
|
|
3495
4028
|
catch: (error) => new SessionStoreError({
|
|
3496
4029
|
message: `Invalid JSON in session file: ${String(error)}`,
|
|
@@ -3499,7 +4032,7 @@ function deserializeSession(json) {
|
|
|
3499
4032
|
})
|
|
3500
4033
|
});
|
|
3501
4034
|
const validated = yield* decodeSession(parsed).pipe(
|
|
3502
|
-
|
|
4035
|
+
Effect13.mapError(
|
|
3503
4036
|
(error) => new SessionStoreError({
|
|
3504
4037
|
message: `Session validation failed: ${String(error)}`,
|
|
3505
4038
|
operation: "get",
|
|
@@ -3510,23 +4043,23 @@ function deserializeSession(json) {
|
|
|
3510
4043
|
return validated;
|
|
3511
4044
|
});
|
|
3512
4045
|
}
|
|
3513
|
-
var
|
|
3514
|
-
create: (originalTask) =>
|
|
3515
|
-
const sessionsDir =
|
|
3516
|
-
yield*
|
|
3517
|
-
const now = yield*
|
|
3518
|
-
const timestampMs =
|
|
4046
|
+
var make5 = {
|
|
4047
|
+
create: (originalTask) => Effect13.gen(function* () {
|
|
4048
|
+
const sessionsDir = join4(process.cwd(), SESSIONS_DIR);
|
|
4049
|
+
yield* ensureDir4(sessionsDir);
|
|
4050
|
+
const now = yield* DateTime5.now;
|
|
4051
|
+
const timestampMs = DateTime5.toEpochMillis(now);
|
|
3519
4052
|
const sessionId = generateSessionId(timestampMs);
|
|
3520
4053
|
const session = {
|
|
3521
4054
|
id: sessionId,
|
|
3522
|
-
createdAt:
|
|
4055
|
+
createdAt: DateTime5.formatIso(now),
|
|
3523
4056
|
status: "active",
|
|
3524
4057
|
originalTask,
|
|
3525
4058
|
completedTasks: []
|
|
3526
4059
|
};
|
|
3527
4060
|
const sessionPath = getSessionPath(sessionId);
|
|
3528
|
-
yield*
|
|
3529
|
-
try: () =>
|
|
4061
|
+
yield* Effect13.tryPromise({
|
|
4062
|
+
try: () => writeFile4(sessionPath, serializeSession(session), "utf-8"),
|
|
3530
4063
|
catch: (error) => new SessionStoreError({
|
|
3531
4064
|
message: `Failed to write session file: ${sessionPath}`,
|
|
3532
4065
|
operation: "create",
|
|
@@ -3535,10 +4068,10 @@ var make3 = {
|
|
|
3535
4068
|
});
|
|
3536
4069
|
return session;
|
|
3537
4070
|
}),
|
|
3538
|
-
get: (sessionId) =>
|
|
4071
|
+
get: (sessionId) => Effect13.gen(function* () {
|
|
3539
4072
|
const sessionPath = getSessionPath(sessionId);
|
|
3540
|
-
const content = yield*
|
|
3541
|
-
try: () =>
|
|
4073
|
+
const content = yield* Effect13.tryPromise({
|
|
4074
|
+
try: () => readFile4(sessionPath, "utf-8"),
|
|
3542
4075
|
catch: (error) => new SessionStoreError({
|
|
3543
4076
|
message: `Failed to read session file: ${sessionPath}`,
|
|
3544
4077
|
operation: "get",
|
|
@@ -3547,10 +4080,10 @@ var make3 = {
|
|
|
3547
4080
|
});
|
|
3548
4081
|
return yield* deserializeSession(content);
|
|
3549
4082
|
}),
|
|
3550
|
-
update: (sessionId, session) =>
|
|
4083
|
+
update: (sessionId, session) => Effect13.gen(function* () {
|
|
3551
4084
|
const sessionPath = getSessionPath(sessionId);
|
|
3552
|
-
yield*
|
|
3553
|
-
try: () =>
|
|
4085
|
+
yield* Effect13.tryPromise({
|
|
4086
|
+
try: () => writeFile4(sessionPath, serializeSession(session), "utf-8"),
|
|
3554
4087
|
catch: (error) => new SessionStoreError({
|
|
3555
4088
|
message: `Failed to update session file: ${sessionPath}`,
|
|
3556
4089
|
operation: "update",
|
|
@@ -3559,37 +4092,37 @@ var make3 = {
|
|
|
3559
4092
|
});
|
|
3560
4093
|
})
|
|
3561
4094
|
};
|
|
3562
|
-
var
|
|
4095
|
+
var Live9 = Layer9.succeed(SessionStore, make5);
|
|
3563
4096
|
var FileSystemSession = {
|
|
3564
|
-
Live:
|
|
4097
|
+
Live: Live9
|
|
3565
4098
|
};
|
|
3566
4099
|
|
|
3567
4100
|
// src/layers/session/memory.ts
|
|
3568
4101
|
init_esm_shims();
|
|
3569
|
-
import { DateTime as
|
|
4102
|
+
import { DateTime as DateTime6, Effect as Effect14, Layer as Layer10, Ref as Ref6 } from "effect";
|
|
3570
4103
|
function createMemorySessionStore(stateRef, counterRef) {
|
|
3571
4104
|
return {
|
|
3572
|
-
create: (originalTask) =>
|
|
3573
|
-
const state = yield*
|
|
3574
|
-
const counter = yield*
|
|
4105
|
+
create: (originalTask) => Effect14.gen(function* () {
|
|
4106
|
+
const state = yield* Ref6.get(stateRef);
|
|
4107
|
+
const counter = yield* Ref6.updateAndGet(counterRef, (n) => n + 1);
|
|
3575
4108
|
const sessionId = `test-session-${counter}`;
|
|
3576
|
-
const now = yield*
|
|
4109
|
+
const now = yield* DateTime6.now;
|
|
3577
4110
|
const session = {
|
|
3578
4111
|
id: sessionId,
|
|
3579
|
-
createdAt:
|
|
4112
|
+
createdAt: DateTime6.formatIso(now),
|
|
3580
4113
|
status: "active",
|
|
3581
4114
|
originalTask,
|
|
3582
4115
|
completedTasks: []
|
|
3583
4116
|
};
|
|
3584
4117
|
state.set(sessionId, session);
|
|
3585
|
-
yield*
|
|
4118
|
+
yield* Ref6.set(stateRef, state);
|
|
3586
4119
|
return session;
|
|
3587
4120
|
}),
|
|
3588
|
-
get: (sessionId) =>
|
|
3589
|
-
const state = yield*
|
|
4121
|
+
get: (sessionId) => Effect14.gen(function* () {
|
|
4122
|
+
const state = yield* Ref6.get(stateRef);
|
|
3590
4123
|
const session = state.get(sessionId);
|
|
3591
4124
|
if (!session) {
|
|
3592
|
-
return yield*
|
|
4125
|
+
return yield* Effect14.fail(
|
|
3593
4126
|
new SessionStoreError({
|
|
3594
4127
|
message: `Session not found: ${sessionId}`,
|
|
3595
4128
|
operation: "get"
|
|
@@ -3598,10 +4131,10 @@ function createMemorySessionStore(stateRef, counterRef) {
|
|
|
3598
4131
|
}
|
|
3599
4132
|
return session;
|
|
3600
4133
|
}),
|
|
3601
|
-
update: (sessionId, session) =>
|
|
3602
|
-
const state = yield*
|
|
4134
|
+
update: (sessionId, session) => Effect14.gen(function* () {
|
|
4135
|
+
const state = yield* Ref6.get(stateRef);
|
|
3603
4136
|
if (!state.has(sessionId)) {
|
|
3604
|
-
return yield*
|
|
4137
|
+
return yield* Effect14.fail(
|
|
3605
4138
|
new SessionStoreError({
|
|
3606
4139
|
message: `Session not found: ${sessionId}`,
|
|
3607
4140
|
operation: "update"
|
|
@@ -3609,34 +4142,34 @@ function createMemorySessionStore(stateRef, counterRef) {
|
|
|
3609
4142
|
);
|
|
3610
4143
|
}
|
|
3611
4144
|
state.set(sessionId, session);
|
|
3612
|
-
yield*
|
|
4145
|
+
yield* Ref6.set(stateRef, state);
|
|
3613
4146
|
})
|
|
3614
4147
|
};
|
|
3615
4148
|
}
|
|
3616
|
-
function
|
|
3617
|
-
return
|
|
4149
|
+
function layer5() {
|
|
4150
|
+
return Layer10.effect(
|
|
3618
4151
|
SessionStore,
|
|
3619
|
-
|
|
3620
|
-
const stateRef = yield*
|
|
3621
|
-
const counterRef = yield*
|
|
4152
|
+
Effect14.gen(function* () {
|
|
4153
|
+
const stateRef = yield* Ref6.make(/* @__PURE__ */ new Map());
|
|
4154
|
+
const counterRef = yield* Ref6.make(0);
|
|
3622
4155
|
return createMemorySessionStore(stateRef, counterRef);
|
|
3623
4156
|
})
|
|
3624
4157
|
);
|
|
3625
4158
|
}
|
|
3626
|
-
var
|
|
4159
|
+
var Live10 = layer5();
|
|
3627
4160
|
var MemorySession = {
|
|
3628
|
-
Live:
|
|
3629
|
-
layer:
|
|
4161
|
+
Live: Live10,
|
|
4162
|
+
layer: layer5
|
|
3630
4163
|
};
|
|
3631
4164
|
|
|
3632
4165
|
// src/layers/signal/ferix-parser.ts
|
|
3633
4166
|
init_esm_shims();
|
|
3634
|
-
import { Effect as
|
|
4167
|
+
import { Effect as Effect15, Layer as Layer11, Ref as Ref7 } from "effect";
|
|
3635
4168
|
|
|
3636
4169
|
// src/services/signal-parser.ts
|
|
3637
4170
|
init_esm_shims();
|
|
3638
|
-
import { Context as
|
|
3639
|
-
var SignalParser = class extends
|
|
4171
|
+
import { Context as Context6 } from "effect";
|
|
4172
|
+
var SignalParser = class extends Context6.Tag("@ferix/SignalParser")() {
|
|
3640
4173
|
};
|
|
3641
4174
|
|
|
3642
4175
|
// src/layers/signal/specs/index.ts
|
|
@@ -3644,7 +4177,7 @@ init_esm_shims();
|
|
|
3644
4177
|
|
|
3645
4178
|
// src/layers/signal/specs/check.ts
|
|
3646
4179
|
init_esm_shims();
|
|
3647
|
-
import { Schema as
|
|
4180
|
+
import { Schema as S15 } from "effect";
|
|
3648
4181
|
|
|
3649
4182
|
// src/layers/signal/specs/registry.ts
|
|
3650
4183
|
init_esm_shims();
|
|
@@ -3701,7 +4234,7 @@ var checkPassedSpec = {
|
|
|
3701
4234
|
parse: (text) => {
|
|
3702
4235
|
if (CHECK_PASSED.test(text)) {
|
|
3703
4236
|
const raw = { _tag: "CheckPassed" };
|
|
3704
|
-
const result =
|
|
4237
|
+
const result = S15.decodeUnknownEither(CheckPassedSignalSchema)(raw);
|
|
3705
4238
|
if (result._tag === "Right") {
|
|
3706
4239
|
return [result.right];
|
|
3707
4240
|
}
|
|
@@ -3717,7 +4250,7 @@ var checkFailedSpec = {
|
|
|
3717
4250
|
parse: (text) => {
|
|
3718
4251
|
if (CHECK_FAILED.test(text)) {
|
|
3719
4252
|
const raw = { _tag: "CheckFailed" };
|
|
3720
|
-
const result =
|
|
4253
|
+
const result = S15.decodeUnknownEither(CheckFailedSignalSchema)(raw);
|
|
3721
4254
|
if (result._tag === "Right") {
|
|
3722
4255
|
return [result.right];
|
|
3723
4256
|
}
|
|
@@ -3731,7 +4264,7 @@ signalSpecRegistry.register(checkFailedSpec);
|
|
|
3731
4264
|
|
|
3732
4265
|
// src/layers/signal/specs/criteria.ts
|
|
3733
4266
|
init_esm_shims();
|
|
3734
|
-
import { Schema as
|
|
4267
|
+
import { Schema as S16 } from "effect";
|
|
3735
4268
|
var CRITERIA_BLOCK = /<ferix:criteria task="(\d+)">([\s\S]*?)<\/ferix:criteria>/g;
|
|
3736
4269
|
var CRITERION = /<criterion id="([^"]+)">([^<]+)<\/criterion>/g;
|
|
3737
4270
|
var CRITERION_PASSED = /<ferix:criterion-passed id="([\d.c]+)"\/>/g;
|
|
@@ -3762,7 +4295,7 @@ var criteriaDefinedSpec = {
|
|
|
3762
4295
|
taskId: match[1],
|
|
3763
4296
|
criteria
|
|
3764
4297
|
};
|
|
3765
|
-
const result =
|
|
4298
|
+
const result = S16.decodeUnknownEither(CriteriaDefinedSignalSchema)(raw);
|
|
3766
4299
|
if (result._tag === "Right") {
|
|
3767
4300
|
signals.push(result.right);
|
|
3768
4301
|
}
|
|
@@ -3781,7 +4314,7 @@ var criterionPassedSpec = {
|
|
|
3781
4314
|
for (const m of text.matchAll(resetRegex(CRITERION_PASSED))) {
|
|
3782
4315
|
if (m[1]) {
|
|
3783
4316
|
const raw = { _tag: "CriterionPassed", criterionId: m[1] };
|
|
3784
|
-
const result =
|
|
4317
|
+
const result = S16.decodeUnknownEither(CriterionPassedSignalSchema)(raw);
|
|
3785
4318
|
if (result._tag === "Right") {
|
|
3786
4319
|
signals.push(result.right);
|
|
3787
4320
|
}
|
|
@@ -3804,7 +4337,7 @@ var criterionFailedSpec = {
|
|
|
3804
4337
|
criterionId: m[1],
|
|
3805
4338
|
reason: m[2] || "Unknown reason"
|
|
3806
4339
|
};
|
|
3807
|
-
const result =
|
|
4340
|
+
const result = S16.decodeUnknownEither(CriterionFailedSignalSchema)(raw);
|
|
3808
4341
|
if (result._tag === "Right") {
|
|
3809
4342
|
signals.push(result.right);
|
|
3810
4343
|
}
|
|
@@ -3818,9 +4351,88 @@ signalSpecRegistry.register(criteriaDefinedSpec);
|
|
|
3818
4351
|
signalSpecRegistry.register(criterionPassedSpec);
|
|
3819
4352
|
signalSpecRegistry.register(criterionFailedSpec);
|
|
3820
4353
|
|
|
4354
|
+
// src/layers/signal/specs/guardrail.ts
|
|
4355
|
+
init_esm_shims();
|
|
4356
|
+
import { Schema as S17 } from "effect";
|
|
4357
|
+
var GUARDRAIL = /<ferix:guardrail\s+severity="(warning|critical)"\s*>([\s\S]*?)<\/ferix:guardrail>/g;
|
|
4358
|
+
var PATTERN = /<pattern>([\s\S]*?)<\/pattern>/;
|
|
4359
|
+
var SIGN = /<sign>([\s\S]*?)<\/sign>/;
|
|
4360
|
+
var AVOIDANCE = /<avoidance>([\s\S]*?)<\/avoidance>/;
|
|
4361
|
+
var guardrailSpec = {
|
|
4362
|
+
tag: "Guardrail",
|
|
4363
|
+
closingTag: "</ferix:guardrail>",
|
|
4364
|
+
schema: GuardrailSignalSchema,
|
|
4365
|
+
parse: (text) => {
|
|
4366
|
+
const signals = [];
|
|
4367
|
+
const matches = text.matchAll(GUARDRAIL);
|
|
4368
|
+
for (const match of matches) {
|
|
4369
|
+
const severity = match[1];
|
|
4370
|
+
const content = match[2] || "";
|
|
4371
|
+
const patternMatch = content.match(PATTERN);
|
|
4372
|
+
const signMatch = content.match(SIGN);
|
|
4373
|
+
const avoidanceMatch = content.match(AVOIDANCE);
|
|
4374
|
+
const pattern = patternMatch?.[1]?.trim() || "";
|
|
4375
|
+
const sign = signMatch?.[1]?.trim() || "";
|
|
4376
|
+
const avoidance = avoidanceMatch?.[1]?.trim() || "";
|
|
4377
|
+
if (!(pattern && sign && avoidance)) {
|
|
4378
|
+
continue;
|
|
4379
|
+
}
|
|
4380
|
+
const raw = {
|
|
4381
|
+
_tag: "Guardrail",
|
|
4382
|
+
pattern,
|
|
4383
|
+
sign,
|
|
4384
|
+
avoidance,
|
|
4385
|
+
severity
|
|
4386
|
+
};
|
|
4387
|
+
const result = S17.decodeUnknownEither(GuardrailSignalSchema)(raw);
|
|
4388
|
+
if (result._tag === "Right") {
|
|
4389
|
+
signals.push(result.right);
|
|
4390
|
+
}
|
|
4391
|
+
}
|
|
4392
|
+
return signals;
|
|
4393
|
+
},
|
|
4394
|
+
keyFields: (s) => s.pattern.slice(0, 50)
|
|
4395
|
+
};
|
|
4396
|
+
signalSpecRegistry.register(guardrailSpec);
|
|
4397
|
+
|
|
4398
|
+
// src/layers/signal/specs/learning.ts
|
|
4399
|
+
init_esm_shims();
|
|
4400
|
+
import { Schema as S18 } from "effect";
|
|
4401
|
+
var LEARNING = /<ferix:learning(?:\s+category="(success|failure|optimization)")?\s*>([\s\S]*?)<\/ferix:learning>/g;
|
|
4402
|
+
var learningSpec = {
|
|
4403
|
+
tag: "Learning",
|
|
4404
|
+
closingTag: "</ferix:learning>",
|
|
4405
|
+
schema: LearningSignalSchema,
|
|
4406
|
+
parse: (text) => {
|
|
4407
|
+
const signals = [];
|
|
4408
|
+
const matches = text.matchAll(LEARNING);
|
|
4409
|
+
for (const match of matches) {
|
|
4410
|
+
const category = match[1];
|
|
4411
|
+
const content = match[2]?.trim() || "";
|
|
4412
|
+
if (!content) {
|
|
4413
|
+
continue;
|
|
4414
|
+
}
|
|
4415
|
+
const raw = {
|
|
4416
|
+
_tag: "Learning",
|
|
4417
|
+
content
|
|
4418
|
+
};
|
|
4419
|
+
if (category) {
|
|
4420
|
+
raw.category = category;
|
|
4421
|
+
}
|
|
4422
|
+
const result = S18.decodeUnknownEither(LearningSignalSchema)(raw);
|
|
4423
|
+
if (result._tag === "Right") {
|
|
4424
|
+
signals.push(result.right);
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
return signals;
|
|
4428
|
+
},
|
|
4429
|
+
keyFields: (s) => s.content.slice(0, 50)
|
|
4430
|
+
};
|
|
4431
|
+
signalSpecRegistry.register(learningSpec);
|
|
4432
|
+
|
|
3821
4433
|
// src/layers/signal/specs/loop-complete.ts
|
|
3822
4434
|
init_esm_shims();
|
|
3823
|
-
import { Schema as
|
|
4435
|
+
import { Schema as S19 } from "effect";
|
|
3824
4436
|
var LOOP_COMPLETE = /<ferix:complete>/;
|
|
3825
4437
|
var loopCompleteSpec = {
|
|
3826
4438
|
tag: "LoopComplete",
|
|
@@ -3829,7 +4441,7 @@ var loopCompleteSpec = {
|
|
|
3829
4441
|
parse: (text) => {
|
|
3830
4442
|
if (LOOP_COMPLETE.test(text)) {
|
|
3831
4443
|
const raw = { _tag: "LoopComplete" };
|
|
3832
|
-
const result =
|
|
4444
|
+
const result = S19.decodeUnknownEither(LoopCompleteSignalSchema)(raw);
|
|
3833
4445
|
if (result._tag === "Right") {
|
|
3834
4446
|
return [result.right];
|
|
3835
4447
|
}
|
|
@@ -3842,7 +4454,7 @@ signalSpecRegistry.register(loopCompleteSpec);
|
|
|
3842
4454
|
|
|
3843
4455
|
// src/layers/signal/specs/phases.ts
|
|
3844
4456
|
init_esm_shims();
|
|
3845
|
-
import { Schema as
|
|
4457
|
+
import { Schema as S20 } from "effect";
|
|
3846
4458
|
var PHASES_BLOCK = /<ferix:phases task="(\d+)">([\s\S]*?)<\/ferix:phases>/;
|
|
3847
4459
|
var PHASE = /<phase id="([\d.]+)">([^<]+)<\/phase>/g;
|
|
3848
4460
|
var PHASE_START = /<ferix:phase-start id="([\d.]+)"\/>/g;
|
|
@@ -3875,7 +4487,7 @@ var phasesDefinedSpec = {
|
|
|
3875
4487
|
taskId: match[1],
|
|
3876
4488
|
phases
|
|
3877
4489
|
};
|
|
3878
|
-
const result =
|
|
4490
|
+
const result = S20.decodeUnknownEither(PhasesDefinedSignalSchema)(raw);
|
|
3879
4491
|
if (result._tag === "Left") {
|
|
3880
4492
|
return [];
|
|
3881
4493
|
}
|
|
@@ -3892,7 +4504,7 @@ var phaseStartedSpec = {
|
|
|
3892
4504
|
for (const m of text.matchAll(resetRegex2(PHASE_START))) {
|
|
3893
4505
|
if (m[1]) {
|
|
3894
4506
|
const raw = { _tag: "PhaseStarted", phaseId: m[1] };
|
|
3895
|
-
const result =
|
|
4507
|
+
const result = S20.decodeUnknownEither(PhaseStartedSignalSchema)(raw);
|
|
3896
4508
|
if (result._tag === "Right") {
|
|
3897
4509
|
signals.push(result.right);
|
|
3898
4510
|
}
|
|
@@ -3911,7 +4523,7 @@ var phaseCompletedSpec = {
|
|
|
3911
4523
|
for (const m of text.matchAll(resetRegex2(PHASE_DONE))) {
|
|
3912
4524
|
if (m[1]) {
|
|
3913
4525
|
const raw = { _tag: "PhaseCompleted", phaseId: m[1] };
|
|
3914
|
-
const result =
|
|
4526
|
+
const result = S20.decodeUnknownEither(PhaseCompletedSignalSchema)(raw);
|
|
3915
4527
|
if (result._tag === "Right") {
|
|
3916
4528
|
signals.push(result.right);
|
|
3917
4529
|
}
|
|
@@ -3934,7 +4546,7 @@ var phaseFailedSpec = {
|
|
|
3934
4546
|
phaseId: m[1],
|
|
3935
4547
|
reason: m[2] || "Unknown reason"
|
|
3936
4548
|
};
|
|
3937
|
-
const result =
|
|
4549
|
+
const result = S20.decodeUnknownEither(PhaseFailedSignalSchema)(raw);
|
|
3938
4550
|
if (result._tag === "Right") {
|
|
3939
4551
|
signals.push(result.right);
|
|
3940
4552
|
}
|
|
@@ -3951,7 +4563,7 @@ signalSpecRegistry.register(phaseFailedSpec);
|
|
|
3951
4563
|
|
|
3952
4564
|
// src/layers/signal/specs/review.ts
|
|
3953
4565
|
init_esm_shims();
|
|
3954
|
-
import { Schema as
|
|
4566
|
+
import { Schema as S21 } from "effect";
|
|
3955
4567
|
var REVIEW_COMPLETE = /<ferix:review-complete\/>/;
|
|
3956
4568
|
var REVIEW_CHANGES = /<ferix:review-changes-made\/>/;
|
|
3957
4569
|
var reviewCompleteSpec = {
|
|
@@ -3964,7 +4576,7 @@ var reviewCompleteSpec = {
|
|
|
3964
4576
|
}
|
|
3965
4577
|
const changesMade = REVIEW_CHANGES.test(text);
|
|
3966
4578
|
const raw = { _tag: "ReviewComplete", changesMade };
|
|
3967
|
-
const result =
|
|
4579
|
+
const result = S21.decodeUnknownEither(ReviewCompleteSignalSchema)(raw);
|
|
3968
4580
|
if (result._tag === "Right") {
|
|
3969
4581
|
return [result.right];
|
|
3970
4582
|
}
|
|
@@ -3976,7 +4588,7 @@ signalSpecRegistry.register(reviewCompleteSpec);
|
|
|
3976
4588
|
|
|
3977
4589
|
// src/layers/signal/specs/task-complete.ts
|
|
3978
4590
|
init_esm_shims();
|
|
3979
|
-
import { Schema as
|
|
4591
|
+
import { Schema as S22 } from "effect";
|
|
3980
4592
|
var TASK_COMPLETE = /<ferix:task-complete id="(\d+)">([\s\S]*?)<\/ferix:task-complete>/;
|
|
3981
4593
|
var SUMMARY = /<summary>([\s\S]*?)<\/summary>/;
|
|
3982
4594
|
var FILES_MODIFIED = /<files-modified>([\s\S]*?)<\/files-modified>/;
|
|
@@ -4007,7 +4619,7 @@ var taskCompleteSpec = {
|
|
|
4007
4619
|
filesModified: parseFileList(filesModifiedMatch?.[1]),
|
|
4008
4620
|
filesCreated: parseFileList(filesCreatedMatch?.[1])
|
|
4009
4621
|
};
|
|
4010
|
-
const result =
|
|
4622
|
+
const result = S22.decodeUnknownEither(TaskCompleteSignalSchema)(raw);
|
|
4011
4623
|
if (result._tag === "Right") {
|
|
4012
4624
|
return [result.right];
|
|
4013
4625
|
}
|
|
@@ -4019,7 +4631,7 @@ signalSpecRegistry.register(taskCompleteSpec);
|
|
|
4019
4631
|
|
|
4020
4632
|
// src/layers/signal/specs/tasks.ts
|
|
4021
4633
|
init_esm_shims();
|
|
4022
|
-
import { Schema as
|
|
4634
|
+
import { Schema as S23 } from "effect";
|
|
4023
4635
|
var TASKS_BLOCK = /<ferix:tasks>([\s\S]*?)<\/ferix:tasks>/;
|
|
4024
4636
|
var TASK = /<task id="(\d+)">([^<]+)<\/task>/g;
|
|
4025
4637
|
function resetRegex3(pattern) {
|
|
@@ -4049,7 +4661,7 @@ var tasksDefinedSpec = {
|
|
|
4049
4661
|
return [];
|
|
4050
4662
|
}
|
|
4051
4663
|
const raw = { _tag: "TasksDefined", tasks };
|
|
4052
|
-
const result =
|
|
4664
|
+
const result = S23.decodeUnknownEither(TasksDefinedSignalSchema)(raw);
|
|
4053
4665
|
if (result._tag === "Left") {
|
|
4054
4666
|
return [];
|
|
4055
4667
|
}
|
|
@@ -4062,20 +4674,20 @@ signalSpecRegistry.register(tasksDefinedSpec);
|
|
|
4062
4674
|
// src/layers/signal/ferix-parser.ts
|
|
4063
4675
|
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
4064
4676
|
function createAccumulatorImpl() {
|
|
4065
|
-
return
|
|
4066
|
-
const chunksRef = yield*
|
|
4067
|
-
const emittedRef = yield*
|
|
4068
|
-
const feed = (text) =>
|
|
4069
|
-
const chunks = yield*
|
|
4677
|
+
return Effect15.gen(function* () {
|
|
4678
|
+
const chunksRef = yield* Ref7.make([]);
|
|
4679
|
+
const emittedRef = yield* Ref7.make(/* @__PURE__ */ new Set());
|
|
4680
|
+
const feed = (text) => Effect15.gen(function* () {
|
|
4681
|
+
const chunks = yield* Ref7.get(chunksRef);
|
|
4070
4682
|
chunks.push(text);
|
|
4071
4683
|
const buffer = chunks.join("");
|
|
4072
4684
|
if (buffer.length > MAX_BUFFER_SIZE) {
|
|
4073
|
-
yield*
|
|
4685
|
+
yield* Ref7.set(chunksRef, [
|
|
4074
4686
|
buffer.slice(buffer.length - MAX_BUFFER_SIZE)
|
|
4075
4687
|
]);
|
|
4076
4688
|
}
|
|
4077
4689
|
const signals = signalSpecRegistry.parseAll(buffer);
|
|
4078
|
-
const emitted = yield*
|
|
4690
|
+
const emitted = yield* Ref7.get(emittedRef);
|
|
4079
4691
|
const newSignals = signals.filter((signal) => {
|
|
4080
4692
|
const key = signalSpecRegistry.getSignalKey(signal);
|
|
4081
4693
|
if (emitted.has(key)) {
|
|
@@ -4087,55 +4699,61 @@ function createAccumulatorImpl() {
|
|
|
4087
4699
|
if (newSignals.length > 0) {
|
|
4088
4700
|
const lastEndPos = signalSpecRegistry.findLastCompleteSignalEnd(buffer);
|
|
4089
4701
|
if (lastEndPos > 0 && lastEndPos < buffer.length) {
|
|
4090
|
-
yield*
|
|
4702
|
+
yield* Ref7.set(chunksRef, [buffer.slice(lastEndPos)]);
|
|
4091
4703
|
}
|
|
4092
4704
|
}
|
|
4093
|
-
yield*
|
|
4705
|
+
yield* Ref7.set(emittedRef, emitted);
|
|
4094
4706
|
return newSignals;
|
|
4095
4707
|
});
|
|
4096
|
-
const flush = () =>
|
|
4097
|
-
const chunks = yield*
|
|
4708
|
+
const flush = () => Effect15.gen(function* () {
|
|
4709
|
+
const chunks = yield* Ref7.get(chunksRef);
|
|
4098
4710
|
const buffer = chunks.join("");
|
|
4099
|
-
yield*
|
|
4100
|
-
const emitted = yield*
|
|
4711
|
+
yield* Ref7.set(chunksRef, []);
|
|
4712
|
+
const emitted = yield* Ref7.get(emittedRef);
|
|
4101
4713
|
const signals = signalSpecRegistry.parseAll(buffer);
|
|
4102
4714
|
const result = signals.filter(
|
|
4103
4715
|
(signal) => !emitted.has(signalSpecRegistry.getSignalKey(signal))
|
|
4104
4716
|
);
|
|
4105
|
-
yield*
|
|
4717
|
+
yield* Ref7.set(emittedRef, /* @__PURE__ */ new Set());
|
|
4106
4718
|
return result;
|
|
4107
4719
|
});
|
|
4108
4720
|
return { feed, flush };
|
|
4109
4721
|
});
|
|
4110
4722
|
}
|
|
4111
|
-
var
|
|
4112
|
-
parse: (text) =>
|
|
4723
|
+
var make6 = {
|
|
4724
|
+
parse: (text) => Effect15.succeed(signalSpecRegistry.parseAll(text)),
|
|
4113
4725
|
createAccumulator: createAccumulatorImpl
|
|
4114
4726
|
};
|
|
4115
|
-
var
|
|
4727
|
+
var Live11 = Layer11.succeed(SignalParser, make6);
|
|
4116
4728
|
var FerixParser = {
|
|
4117
|
-
Live:
|
|
4729
|
+
Live: Live11
|
|
4118
4730
|
};
|
|
4119
4731
|
|
|
4120
4732
|
// src/layers/index.ts
|
|
4121
|
-
var ProductionLayers =
|
|
4733
|
+
var ProductionLayers = Layer12.mergeAll(
|
|
4122
4734
|
ClaudeCLI.Live,
|
|
4123
4735
|
FerixParser.Live,
|
|
4124
4736
|
FileSystemPlan.Live,
|
|
4125
|
-
FileSystemSession.Live
|
|
4737
|
+
FileSystemSession.Live,
|
|
4738
|
+
FileSystemProgress.Live,
|
|
4739
|
+
FileSystemGuardrails.Live
|
|
4126
4740
|
);
|
|
4127
|
-
var TestLayers =
|
|
4741
|
+
var TestLayers = Layer12.mergeAll(
|
|
4128
4742
|
Mock.Live,
|
|
4129
4743
|
FerixParser.Live,
|
|
4130
4744
|
MemoryPlan.Live,
|
|
4131
|
-
MemorySession.Live
|
|
4745
|
+
MemorySession.Live,
|
|
4746
|
+
MemoryProgress.Live,
|
|
4747
|
+
MemoryGuardrails.Live
|
|
4132
4748
|
);
|
|
4133
4749
|
function createTestLayers(events) {
|
|
4134
|
-
return
|
|
4750
|
+
return Layer12.mergeAll(
|
|
4135
4751
|
Mock.layer({ events }),
|
|
4136
4752
|
FerixParser.Live,
|
|
4137
4753
|
MemoryPlan.layer(),
|
|
4138
|
-
MemorySession.layer()
|
|
4754
|
+
MemorySession.layer(),
|
|
4755
|
+
MemoryProgress.layer(),
|
|
4756
|
+
MemoryGuardrails.layer()
|
|
4139
4757
|
);
|
|
4140
4758
|
}
|
|
4141
4759
|
|
|
@@ -4144,42 +4762,42 @@ init_esm_shims();
|
|
|
4144
4762
|
|
|
4145
4763
|
// src/orchestrator/loop.ts
|
|
4146
4764
|
init_esm_shims();
|
|
4147
|
-
import { DateTime as
|
|
4765
|
+
import { DateTime as DateTime10, Effect as Effect20, Option, pipe as pipe3, Ref as Ref11, Stream as Stream9 } from "effect";
|
|
4148
4766
|
|
|
4149
4767
|
// src/orchestrator/discovery.ts
|
|
4150
4768
|
init_esm_shims();
|
|
4151
|
-
import { DateTime as
|
|
4769
|
+
import { DateTime as DateTime8, Effect as Effect18, pipe, Ref as Ref9, Stream as Stream7 } from "effect";
|
|
4152
4770
|
|
|
4153
4771
|
// src/layers/plan/task-generation.ts
|
|
4154
4772
|
init_esm_shims();
|
|
4155
|
-
import { mkdir as
|
|
4156
|
-
import { join as
|
|
4157
|
-
import { Effect as
|
|
4158
|
-
var
|
|
4159
|
-
function
|
|
4160
|
-
return
|
|
4161
|
-
try: () =>
|
|
4773
|
+
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
4774
|
+
import { join as join5 } from "path";
|
|
4775
|
+
import { Effect as Effect16 } from "effect";
|
|
4776
|
+
var PLANS_DIR4 = ".ferix/plans";
|
|
4777
|
+
function ensureDir5(dirPath) {
|
|
4778
|
+
return Effect16.tryPromise({
|
|
4779
|
+
try: () => mkdir5(dirPath, { recursive: true }),
|
|
4162
4780
|
catch: (error) => new PlanStoreError({
|
|
4163
4781
|
message: `Failed to create directory: ${dirPath}`,
|
|
4164
4782
|
operation: "create",
|
|
4165
4783
|
cause: error
|
|
4166
4784
|
})
|
|
4167
|
-
}).pipe(
|
|
4785
|
+
}).pipe(Effect16.asVoid);
|
|
4168
4786
|
}
|
|
4169
|
-
function
|
|
4170
|
-
return
|
|
4787
|
+
function getSessionDir4(sessionId) {
|
|
4788
|
+
return join5(process.cwd(), PLANS_DIR4, sessionId);
|
|
4171
4789
|
}
|
|
4172
4790
|
function getTasksMdPath(sessionId) {
|
|
4173
|
-
return
|
|
4791
|
+
return join5(getSessionDir4(sessionId), "tasks.md");
|
|
4174
4792
|
}
|
|
4175
4793
|
function writeTasksMd(sessionId, tasks) {
|
|
4176
|
-
return
|
|
4177
|
-
const sessionDir =
|
|
4178
|
-
yield*
|
|
4794
|
+
return Effect16.gen(function* () {
|
|
4795
|
+
const sessionDir = getSessionDir4(sessionId);
|
|
4796
|
+
yield* ensureDir5(sessionDir);
|
|
4179
4797
|
const tasksMdPath = getTasksMdPath(sessionId);
|
|
4180
4798
|
const content = formatTasksMd(tasks);
|
|
4181
|
-
yield*
|
|
4182
|
-
try: () =>
|
|
4799
|
+
yield* Effect16.tryPromise({
|
|
4800
|
+
try: () => writeFile5(tasksMdPath, content, "utf-8"),
|
|
4183
4801
|
catch: (error) => new PlanStoreError({
|
|
4184
4802
|
message: `Failed to write tasks.md: ${tasksMdPath}`,
|
|
4185
4803
|
operation: "create",
|
|
@@ -4323,6 +4941,32 @@ eventMappingRegistry.registerSignalMapper({
|
|
|
4323
4941
|
}
|
|
4324
4942
|
})
|
|
4325
4943
|
});
|
|
4944
|
+
eventMappingRegistry.registerSignalMapper({
|
|
4945
|
+
tag: "Learning",
|
|
4946
|
+
map: (signal, context) => ({
|
|
4947
|
+
_tag: "LearningRecorded",
|
|
4948
|
+
iteration: 0,
|
|
4949
|
+
// Will be overwritten by iteration stream
|
|
4950
|
+
content: signal.content,
|
|
4951
|
+
category: signal.category,
|
|
4952
|
+
timestamp: context.timestamp
|
|
4953
|
+
})
|
|
4954
|
+
});
|
|
4955
|
+
eventMappingRegistry.registerSignalMapper({
|
|
4956
|
+
tag: "Guardrail",
|
|
4957
|
+
map: (signal, context) => ({
|
|
4958
|
+
_tag: "GuardrailAdded",
|
|
4959
|
+
id: `gr-pending-${context.timestamp}`,
|
|
4960
|
+
// Temp ID, real one assigned in iteration
|
|
4961
|
+
iteration: 0,
|
|
4962
|
+
// Will be overwritten by iteration stream
|
|
4963
|
+
pattern: signal.pattern,
|
|
4964
|
+
sign: signal.sign,
|
|
4965
|
+
avoidance: signal.avoidance,
|
|
4966
|
+
severity: signal.severity,
|
|
4967
|
+
timestamp: context.timestamp
|
|
4968
|
+
})
|
|
4969
|
+
});
|
|
4326
4970
|
|
|
4327
4971
|
// src/orchestrator/mapping/index.ts
|
|
4328
4972
|
function mapLLMEventToDomain(event, context) {
|
|
@@ -4334,7 +4978,7 @@ function mapSignalToDomain(signal, context) {
|
|
|
4334
4978
|
|
|
4335
4979
|
// src/orchestrator/plan-updates.ts
|
|
4336
4980
|
init_esm_shims();
|
|
4337
|
-
import { DateTime as
|
|
4981
|
+
import { DateTime as DateTime7, Effect as Effect17, Ref as Ref8 } from "effect";
|
|
4338
4982
|
|
|
4339
4983
|
// src/orchestrator/plan-updates/index.ts
|
|
4340
4984
|
init_esm_shims();
|
|
@@ -4546,6 +5190,20 @@ planUpdateRegistry.register({
|
|
|
4546
5190
|
} : void 0
|
|
4547
5191
|
});
|
|
4548
5192
|
|
|
5193
|
+
// src/orchestrator/plan-updates/handlers/guardrail.ts
|
|
5194
|
+
init_esm_shims();
|
|
5195
|
+
planUpdateRegistry.register({
|
|
5196
|
+
tag: "Guardrail",
|
|
5197
|
+
handle: (_signal, _currentPlan, _context) => void 0
|
|
5198
|
+
});
|
|
5199
|
+
|
|
5200
|
+
// src/orchestrator/plan-updates/handlers/learning.ts
|
|
5201
|
+
init_esm_shims();
|
|
5202
|
+
planUpdateRegistry.register({
|
|
5203
|
+
tag: "Learning",
|
|
5204
|
+
handle: (_signal, _currentPlan, _context) => void 0
|
|
5205
|
+
});
|
|
5206
|
+
|
|
4549
5207
|
// src/orchestrator/plan-updates/handlers/phase-lifecycle.ts
|
|
4550
5208
|
init_esm_shims();
|
|
4551
5209
|
planUpdateRegistry.register({
|
|
@@ -4625,9 +5283,9 @@ function persistPlanUpdate(planStore, plan, operation) {
|
|
|
4625
5283
|
tasks: plan.tasks
|
|
4626
5284
|
}) : planStore.update(plan.id, plan);
|
|
4627
5285
|
return storeOp.pipe(
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
(error) =>
|
|
5286
|
+
Effect17.map(() => null),
|
|
5287
|
+
Effect17.catchAll(
|
|
5288
|
+
(error) => Effect17.succeed({
|
|
4631
5289
|
_tag: "PlanUpdateFailed",
|
|
4632
5290
|
operation,
|
|
4633
5291
|
error: error.message,
|
|
@@ -4637,10 +5295,10 @@ function persistPlanUpdate(planStore, plan, operation) {
|
|
|
4637
5295
|
);
|
|
4638
5296
|
}
|
|
4639
5297
|
function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessionId, originalTask) {
|
|
4640
|
-
return
|
|
4641
|
-
const currentPlan = yield*
|
|
4642
|
-
const now = yield*
|
|
4643
|
-
const timestamp =
|
|
5298
|
+
return Effect17.gen(function* () {
|
|
5299
|
+
const currentPlan = yield* Ref8.get(currentPlanRef);
|
|
5300
|
+
const now = yield* DateTime7.now;
|
|
5301
|
+
const timestamp = DateTime7.formatIso(now);
|
|
4644
5302
|
const updateResult = computePlanUpdate(signal, currentPlan, {
|
|
4645
5303
|
sessionId,
|
|
4646
5304
|
originalTask,
|
|
@@ -4650,8 +5308,8 @@ function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessi
|
|
|
4650
5308
|
return [];
|
|
4651
5309
|
}
|
|
4652
5310
|
const { plan, operation, eventTag } = updateResult;
|
|
4653
|
-
yield*
|
|
4654
|
-
yield*
|
|
5311
|
+
yield* Ref8.set(currentPlanRef, plan);
|
|
5312
|
+
yield* Ref8.update(persistenceStateRef, (state) => ({
|
|
4655
5313
|
dirty: true,
|
|
4656
5314
|
pendingOperation: state.pendingOperation === "create" ? "create" : operation
|
|
4657
5315
|
}));
|
|
@@ -4659,12 +5317,12 @@ function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessi
|
|
|
4659
5317
|
});
|
|
4660
5318
|
}
|
|
4661
5319
|
function flushPlanPersistence(planStore, currentPlanRef, persistenceStateRef) {
|
|
4662
|
-
return
|
|
4663
|
-
const state = yield*
|
|
5320
|
+
return Effect17.gen(function* () {
|
|
5321
|
+
const state = yield* Ref8.get(persistenceStateRef);
|
|
4664
5322
|
if (!(state.dirty && state.pendingOperation)) {
|
|
4665
5323
|
return [];
|
|
4666
5324
|
}
|
|
4667
|
-
const plan = yield*
|
|
5325
|
+
const plan = yield* Ref8.get(currentPlanRef);
|
|
4668
5326
|
if (!plan) {
|
|
4669
5327
|
return [];
|
|
4670
5328
|
}
|
|
@@ -4677,7 +5335,7 @@ function flushPlanPersistence(planStore, currentPlanRef, persistenceStateRef) {
|
|
|
4677
5335
|
if (failureEvent) {
|
|
4678
5336
|
events.push(failureEvent);
|
|
4679
5337
|
}
|
|
4680
|
-
yield*
|
|
5338
|
+
yield* Ref8.set(persistenceStateRef, {
|
|
4681
5339
|
dirty: false,
|
|
4682
5340
|
pendingOperation: null
|
|
4683
5341
|
});
|
|
@@ -4927,12 +5585,12 @@ Begin.`);
|
|
|
4927
5585
|
|
|
4928
5586
|
// src/orchestrator/discovery.ts
|
|
4929
5587
|
function processTextSignals(signalParser, text, context) {
|
|
4930
|
-
return
|
|
5588
|
+
return Effect18.gen(function* () {
|
|
4931
5589
|
const events = [];
|
|
4932
5590
|
const parsedSignals = [];
|
|
4933
5591
|
const signals = yield* signalParser.parse(text).pipe(
|
|
4934
|
-
|
|
4935
|
-
(error) =>
|
|
5592
|
+
Effect18.tapError(
|
|
5593
|
+
(error) => Effect18.logDebug(
|
|
4936
5594
|
"Signal parsing failed, continuing with empty signals",
|
|
4937
5595
|
{
|
|
4938
5596
|
error: String(error),
|
|
@@ -4940,7 +5598,7 @@ function processTextSignals(signalParser, text, context) {
|
|
|
4940
5598
|
}
|
|
4941
5599
|
)
|
|
4942
5600
|
),
|
|
4943
|
-
|
|
5601
|
+
Effect18.orElseSucceed(() => [])
|
|
4944
5602
|
);
|
|
4945
5603
|
for (const signal of signals) {
|
|
4946
5604
|
events.push(mapSignalToDomain(signal, context));
|
|
@@ -4950,7 +5608,7 @@ function processTextSignals(signalParser, text, context) {
|
|
|
4950
5608
|
});
|
|
4951
5609
|
}
|
|
4952
5610
|
function processLLMEvent(signalParser, llmEvent, context) {
|
|
4953
|
-
return
|
|
5611
|
+
return Effect18.gen(function* () {
|
|
4954
5612
|
const domainEvent = mapLLMEventToDomain(llmEvent, context);
|
|
4955
5613
|
const events = [domainEvent];
|
|
4956
5614
|
const allSignals = [];
|
|
@@ -4995,10 +5653,10 @@ function planTasksToGeneratedTasks(plan) {
|
|
|
4995
5653
|
}
|
|
4996
5654
|
function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, config, sessionId) {
|
|
4997
5655
|
return Stream7.unwrap(
|
|
4998
|
-
|
|
4999
|
-
const startTimeUtc = yield*
|
|
5000
|
-
const startTime =
|
|
5001
|
-
const persistenceStateRef = yield*
|
|
5656
|
+
Effect18.gen(function* () {
|
|
5657
|
+
const startTimeUtc = yield* DateTime8.now;
|
|
5658
|
+
const startTime = DateTime8.toEpochMillis(startTimeUtc);
|
|
5659
|
+
const persistenceStateRef = yield* Ref9.make({
|
|
5002
5660
|
dirty: false,
|
|
5003
5661
|
pendingOperation: null
|
|
5004
5662
|
});
|
|
@@ -5022,10 +5680,10 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
|
|
|
5022
5680
|
),
|
|
5023
5681
|
Stream7.flatMap(
|
|
5024
5682
|
(llmEvent) => Stream7.unwrap(
|
|
5025
|
-
|
|
5026
|
-
const now = yield*
|
|
5683
|
+
Effect18.gen(function* () {
|
|
5684
|
+
const now = yield* DateTime8.now;
|
|
5027
5685
|
const context = {
|
|
5028
|
-
timestamp:
|
|
5686
|
+
timestamp: DateTime8.toEpochMillis(now)
|
|
5029
5687
|
};
|
|
5030
5688
|
const result = yield* processLLMEvent(
|
|
5031
5689
|
signalParser,
|
|
@@ -5059,27 +5717,27 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
|
|
|
5059
5717
|
)
|
|
5060
5718
|
);
|
|
5061
5719
|
const completionStream = Stream7.fromEffect(
|
|
5062
|
-
|
|
5720
|
+
Effect18.gen(function* () {
|
|
5063
5721
|
const persistEvents = yield* flushPlanPersistence(
|
|
5064
5722
|
planStore,
|
|
5065
5723
|
currentPlanRef,
|
|
5066
5724
|
persistenceStateRef
|
|
5067
5725
|
);
|
|
5068
|
-
const plan = yield*
|
|
5726
|
+
const plan = yield* Ref9.get(currentPlanRef);
|
|
5069
5727
|
const taskCount = plan?.tasks.length ?? 0;
|
|
5070
5728
|
if (plan && plan.tasks.length > 0) {
|
|
5071
5729
|
const generatedTasks = planTasksToGeneratedTasks(plan);
|
|
5072
5730
|
yield* writeTasksMd(sessionId, generatedTasks).pipe(
|
|
5073
|
-
|
|
5074
|
-
(error) =>
|
|
5731
|
+
Effect18.tapError(
|
|
5732
|
+
(error) => Effect18.logDebug("Failed to write tasks.md, continuing", {
|
|
5075
5733
|
error: String(error)
|
|
5076
5734
|
})
|
|
5077
5735
|
),
|
|
5078
|
-
|
|
5736
|
+
Effect18.orElseSucceed(() => void 0)
|
|
5079
5737
|
);
|
|
5080
5738
|
}
|
|
5081
|
-
const endTimeUtc = yield*
|
|
5082
|
-
const endTime =
|
|
5739
|
+
const endTimeUtc = yield* DateTime8.now;
|
|
5740
|
+
const endTime = DateTime8.toEpochMillis(endTimeUtc);
|
|
5083
5741
|
const discoveryCompleted = {
|
|
5084
5742
|
_tag: "DiscoveryCompleted",
|
|
5085
5743
|
taskCount,
|
|
@@ -5100,15 +5758,15 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
|
|
|
5100
5758
|
|
|
5101
5759
|
// src/orchestrator/iteration.ts
|
|
5102
5760
|
init_esm_shims();
|
|
5103
|
-
import { DateTime as
|
|
5761
|
+
import { DateTime as DateTime9, Effect as Effect19, pipe as pipe2, Ref as Ref10, Stream as Stream8 } from "effect";
|
|
5104
5762
|
function processTextSignals2(signalParser, text, context) {
|
|
5105
|
-
return
|
|
5763
|
+
return Effect19.gen(function* () {
|
|
5106
5764
|
const events = [];
|
|
5107
5765
|
let completed = false;
|
|
5108
5766
|
const parsedSignals = [];
|
|
5109
5767
|
const signals = yield* signalParser.parse(text).pipe(
|
|
5110
|
-
|
|
5111
|
-
(error) =>
|
|
5768
|
+
Effect19.tapError(
|
|
5769
|
+
(error) => Effect19.logDebug(
|
|
5112
5770
|
"Signal parsing failed, continuing with empty signals",
|
|
5113
5771
|
{
|
|
5114
5772
|
error: String(error),
|
|
@@ -5116,7 +5774,7 @@ function processTextSignals2(signalParser, text, context) {
|
|
|
5116
5774
|
}
|
|
5117
5775
|
)
|
|
5118
5776
|
),
|
|
5119
|
-
|
|
5777
|
+
Effect19.orElseSucceed(() => [])
|
|
5120
5778
|
);
|
|
5121
5779
|
for (const signal of signals) {
|
|
5122
5780
|
events.push(mapSignalToDomain(signal, context));
|
|
@@ -5129,7 +5787,7 @@ function processTextSignals2(signalParser, text, context) {
|
|
|
5129
5787
|
});
|
|
5130
5788
|
}
|
|
5131
5789
|
function processLLMEvent2(signalParser, llmEvent, context) {
|
|
5132
|
-
return
|
|
5790
|
+
return Effect19.gen(function* () {
|
|
5133
5791
|
const domainEvent = mapLLMEventToDomain(llmEvent, context);
|
|
5134
5792
|
const events = [domainEvent];
|
|
5135
5793
|
let completed = false;
|
|
@@ -5162,9 +5820,9 @@ function processLLMEvent2(signalParser, llmEvent, context) {
|
|
|
5162
5820
|
}
|
|
5163
5821
|
function createIterationStream(llm, signalParser, planStore, currentPlanRef, loopCompletedRef, config, iteration, sessionId) {
|
|
5164
5822
|
return Stream8.unwrap(
|
|
5165
|
-
|
|
5166
|
-
const currentPlan = yield*
|
|
5167
|
-
const persistenceStateRef = yield*
|
|
5823
|
+
Effect19.gen(function* () {
|
|
5824
|
+
const currentPlan = yield* Ref10.get(currentPlanRef);
|
|
5825
|
+
const persistenceStateRef = yield* Ref10.make({
|
|
5168
5826
|
dirty: false,
|
|
5169
5827
|
pendingOperation: null
|
|
5170
5828
|
});
|
|
@@ -5182,10 +5840,10 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
|
|
|
5182
5840
|
),
|
|
5183
5841
|
Stream8.flatMap(
|
|
5184
5842
|
(llmEvent) => Stream8.unwrap(
|
|
5185
|
-
|
|
5186
|
-
const now = yield*
|
|
5843
|
+
Effect19.gen(function* () {
|
|
5844
|
+
const now = yield* DateTime9.now;
|
|
5187
5845
|
const context = {
|
|
5188
|
-
timestamp:
|
|
5846
|
+
timestamp: DateTime9.toEpochMillis(now)
|
|
5189
5847
|
};
|
|
5190
5848
|
const result = yield* processLLMEvent2(
|
|
5191
5849
|
signalParser,
|
|
@@ -5204,7 +5862,7 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
|
|
|
5204
5862
|
events.push(...planEvents);
|
|
5205
5863
|
}
|
|
5206
5864
|
if (result.completed) {
|
|
5207
|
-
yield*
|
|
5865
|
+
yield* Ref10.set(loopCompletedRef, true);
|
|
5208
5866
|
}
|
|
5209
5867
|
return Stream8.fromIterable(events);
|
|
5210
5868
|
})
|
|
@@ -5223,7 +5881,7 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
|
|
|
5223
5881
|
)
|
|
5224
5882
|
);
|
|
5225
5883
|
const completionStream = Stream8.fromEffect(
|
|
5226
|
-
|
|
5884
|
+
Effect19.gen(function* () {
|
|
5227
5885
|
const persistEvents = yield* flushPlanPersistence(
|
|
5228
5886
|
planStore,
|
|
5229
5887
|
currentPlanRef,
|
|
@@ -5248,13 +5906,13 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
|
|
|
5248
5906
|
// src/orchestrator/loop.ts
|
|
5249
5907
|
function runLoop(config) {
|
|
5250
5908
|
return Stream9.unwrap(
|
|
5251
|
-
|
|
5909
|
+
Effect20.gen(function* () {
|
|
5252
5910
|
const llm = yield* LLM;
|
|
5253
5911
|
const signalParser = yield* SignalParser;
|
|
5254
5912
|
const sessionStore = yield* SessionStore;
|
|
5255
5913
|
const planStore = yield* PlanStore;
|
|
5256
5914
|
const session = yield* sessionStore.create(config.task).pipe(
|
|
5257
|
-
|
|
5915
|
+
Effect20.mapError(
|
|
5258
5916
|
(e) => new OrchestratorError({
|
|
5259
5917
|
message: `Failed to create session: ${e.message}`,
|
|
5260
5918
|
phase: "setup",
|
|
@@ -5262,10 +5920,10 @@ function runLoop(config) {
|
|
|
5262
5920
|
})
|
|
5263
5921
|
)
|
|
5264
5922
|
);
|
|
5265
|
-
const startTimeUtc = yield*
|
|
5266
|
-
const startTime =
|
|
5267
|
-
const loopCompletedRef = yield*
|
|
5268
|
-
const currentPlanRef = yield*
|
|
5923
|
+
const startTimeUtc = yield* DateTime10.now;
|
|
5924
|
+
const startTime = DateTime10.toEpochMillis(startTimeUtc);
|
|
5925
|
+
const loopCompletedRef = yield* Ref11.make(false);
|
|
5926
|
+
const currentPlanRef = yield* Ref11.make(void 0);
|
|
5269
5927
|
const maxIterations = config.maxIterations === 0 ? Number.POSITIVE_INFINITY : config.maxIterations;
|
|
5270
5928
|
const loopStarted = {
|
|
5271
5929
|
_tag: "LoopStarted",
|
|
@@ -5282,8 +5940,8 @@ function runLoop(config) {
|
|
|
5282
5940
|
);
|
|
5283
5941
|
const iterationsStream = Stream9.unfoldEffect(
|
|
5284
5942
|
1,
|
|
5285
|
-
(iteration) =>
|
|
5286
|
-
const completed = yield*
|
|
5943
|
+
(iteration) => Effect20.gen(function* () {
|
|
5944
|
+
const completed = yield* Ref11.get(loopCompletedRef);
|
|
5287
5945
|
if (completed || iteration > maxIterations) {
|
|
5288
5946
|
return Option.none();
|
|
5289
5947
|
}
|
|
@@ -5318,8 +5976,8 @@ function runLoop(config) {
|
|
|
5318
5976
|
);
|
|
5319
5977
|
}).pipe(
|
|
5320
5978
|
// Also catch setup errors (e.g., session creation failure)
|
|
5321
|
-
|
|
5322
|
-
(error) =>
|
|
5979
|
+
Effect20.catchAll(
|
|
5980
|
+
(error) => Effect20.succeed(
|
|
5323
5981
|
Stream9.succeed({
|
|
5324
5982
|
_tag: "LoopFailed",
|
|
5325
5983
|
error: {
|
|
@@ -5334,10 +5992,10 @@ function runLoop(config) {
|
|
|
5334
5992
|
}
|
|
5335
5993
|
function createCompletionStream(sessionStore, session, config, startTime, loopCompletedRef) {
|
|
5336
5994
|
return Stream9.fromEffect(
|
|
5337
|
-
|
|
5338
|
-
const endTimeUtc = yield*
|
|
5339
|
-
const durationMs =
|
|
5340
|
-
const completed = yield*
|
|
5995
|
+
Effect20.gen(function* () {
|
|
5996
|
+
const endTimeUtc = yield* DateTime10.now;
|
|
5997
|
+
const durationMs = DateTime10.toEpochMillis(endTimeUtc) - startTime;
|
|
5998
|
+
const completed = yield* Ref11.get(loopCompletedRef);
|
|
5341
5999
|
const summary = {
|
|
5342
6000
|
iterations: config.maxIterations,
|
|
5343
6001
|
success: completed,
|
|
@@ -5349,13 +6007,13 @@ function createCompletionStream(sessionStore, session, config, startTime, loopCo
|
|
|
5349
6007
|
...session,
|
|
5350
6008
|
status: completed ? "completed" : "paused"
|
|
5351
6009
|
}).pipe(
|
|
5352
|
-
|
|
5353
|
-
(error) =>
|
|
6010
|
+
Effect20.tapError(
|
|
6011
|
+
(error) => Effect20.logDebug("Session update failed, continuing", {
|
|
5354
6012
|
sessionId: session.id,
|
|
5355
6013
|
error: String(error)
|
|
5356
6014
|
})
|
|
5357
6015
|
),
|
|
5358
|
-
|
|
6016
|
+
Effect20.orElseSucceed(() => void 0)
|
|
5359
6017
|
);
|
|
5360
6018
|
const event = { _tag: "LoopCompleted", summary };
|
|
5361
6019
|
return event;
|
|
@@ -5367,7 +6025,7 @@ function createCompletionStream(sessionStore, session, config, startTime, loopCo
|
|
|
5367
6025
|
function run(options) {
|
|
5368
6026
|
const { config, consumer: consumerType = "headless", onEvent } = options;
|
|
5369
6027
|
const events = runLoop(config);
|
|
5370
|
-
const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) =>
|
|
6028
|
+
const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect21.sync(() => onEvent(event)))) : events;
|
|
5371
6029
|
const eventsWithLayers = eventsWithCallback.pipe(
|
|
5372
6030
|
Stream10.provideLayer(ProductionLayers)
|
|
5373
6031
|
);
|
|
@@ -5380,7 +6038,7 @@ function run(options) {
|
|
|
5380
6038
|
function runTest(options, mockEvents) {
|
|
5381
6039
|
const { config, onEvent } = options;
|
|
5382
6040
|
const events = runLoop(config);
|
|
5383
|
-
const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) =>
|
|
6041
|
+
const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect21.sync(() => onEvent(event)))) : events;
|
|
5384
6042
|
const layers = mockEvents ? createTestLayers(mockEvents) : TestLayers;
|
|
5385
6043
|
const eventsWithLayers = eventsWithCallback.pipe(Stream10.provideLayer(layers));
|
|
5386
6044
|
return eventsWithLayers.pipe(Stream10.runDrain);
|
|
@@ -5388,11 +6046,11 @@ function runTest(options, mockEvents) {
|
|
|
5388
6046
|
function collectEvents(config, mockEvents) {
|
|
5389
6047
|
const events = runLoop(config);
|
|
5390
6048
|
const layers = mockEvents ? createTestLayers(mockEvents) : TestLayers;
|
|
5391
|
-
return events.pipe(Stream10.provideLayer(layers), Stream10.runCollect).pipe(
|
|
6049
|
+
return events.pipe(Stream10.provideLayer(layers), Stream10.runCollect).pipe(Effect21.map((chunk) => Array.from(chunk)));
|
|
5392
6050
|
}
|
|
5393
6051
|
function main(config) {
|
|
5394
6052
|
const consumerType = process.stdout.isTTY ? "tui" : "headless";
|
|
5395
|
-
return run({ config, consumer: consumerType }).pipe(
|
|
6053
|
+
return run({ config, consumer: consumerType }).pipe(Effect21.runPromise);
|
|
5396
6054
|
}
|
|
5397
6055
|
|
|
5398
6056
|
// src/services/index.ts
|
|
@@ -5445,11 +6103,20 @@ export {
|
|
|
5445
6103
|
ExecutionModeSchema,
|
|
5446
6104
|
FerixParser,
|
|
5447
6105
|
FileLoggerConfigSchema,
|
|
6106
|
+
FileSystemGuardrails,
|
|
5448
6107
|
FileSystemPlan,
|
|
6108
|
+
FileSystemProgress,
|
|
5449
6109
|
FileSystemSession,
|
|
5450
6110
|
GeneratedTaskListSchema,
|
|
5451
6111
|
GeneratedTaskSchema,
|
|
5452
6112
|
GeneratedTaskStatusSchema,
|
|
6113
|
+
GuardrailAddedEventSchema,
|
|
6114
|
+
GuardrailSchema,
|
|
6115
|
+
GuardrailSeveritySchema,
|
|
6116
|
+
GuardrailSignalSchema,
|
|
6117
|
+
GuardrailsFileSchema,
|
|
6118
|
+
GuardrailsStore,
|
|
6119
|
+
GuardrailsStoreError,
|
|
5453
6120
|
IterationCompletedEventSchema,
|
|
5454
6121
|
IterationStartedEventSchema,
|
|
5455
6122
|
LLM,
|
|
@@ -5459,6 +6126,9 @@ export {
|
|
|
5459
6126
|
LLMToolEndEventSchema,
|
|
5460
6127
|
LLMToolStartEventSchema,
|
|
5461
6128
|
LLMToolUseEventSchema,
|
|
6129
|
+
LearningCategorySchema,
|
|
6130
|
+
LearningRecordedEventSchema,
|
|
6131
|
+
LearningSignalSchema,
|
|
5462
6132
|
LogEntrySchema,
|
|
5463
6133
|
LogLevelSchema,
|
|
5464
6134
|
LoopCompleteSignalSchema,
|
|
@@ -5469,7 +6139,9 @@ export {
|
|
|
5469
6139
|
LoopStartedEventSchema,
|
|
5470
6140
|
LoopStatusSchema,
|
|
5471
6141
|
LoopSummarySchema,
|
|
6142
|
+
MemoryGuardrails,
|
|
5472
6143
|
MemoryPlan,
|
|
6144
|
+
MemoryProgress,
|
|
5473
6145
|
MemorySession,
|
|
5474
6146
|
Mock,
|
|
5475
6147
|
Mock as MockLLM,
|
|
@@ -5499,6 +6171,12 @@ export {
|
|
|
5499
6171
|
PlanUpdateFailedEventSchema,
|
|
5500
6172
|
PlanUpdatedEventSchema,
|
|
5501
6173
|
ProductionLayers,
|
|
6174
|
+
ProgressActionSchema,
|
|
6175
|
+
ProgressEntrySchema,
|
|
6176
|
+
ProgressFileSchema,
|
|
6177
|
+
ProgressStore,
|
|
6178
|
+
ProgressStoreError,
|
|
6179
|
+
ProgressUpdatedEventSchema,
|
|
5502
6180
|
PromptConfigSchema,
|
|
5503
6181
|
ReviewCompleteDataSchema,
|
|
5504
6182
|
ReviewCompleteEventSchema,
|
|
@@ -5538,10 +6216,14 @@ export {
|
|
|
5538
6216
|
createHeadlessConsumer,
|
|
5539
6217
|
createTUIConsumer,
|
|
5540
6218
|
createTestLayers,
|
|
6219
|
+
decodeGuardrail,
|
|
6220
|
+
decodeGuardrailsFile,
|
|
5541
6221
|
decodeLLMEvent,
|
|
5542
6222
|
decodeLoopConfig,
|
|
5543
6223
|
decodePlan,
|
|
5544
6224
|
decodePlanData,
|
|
6225
|
+
decodeProgressEntry,
|
|
6226
|
+
decodeProgressFile,
|
|
5545
6227
|
decodeSession,
|
|
5546
6228
|
decodeSignal,
|
|
5547
6229
|
decodeSignalSync,
|