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