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