ferix-code 0.0.2-beta.6 → 0.0.2-beta.9

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +226 -20
  2. package/dist/index.js +737 -302
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -71,7 +71,7 @@ import { Command } from "commander";
71
71
  // package.json
72
72
  var package_default = {
73
73
  name: "ferix-code",
74
- version: "0.0.2-beta.6",
74
+ version: "0.0.2-beta.9",
75
75
  description: "Composable RALPH loops for AI coding agents - v2 with Effect",
76
76
  type: "module",
77
77
  bin: {
@@ -118,7 +118,7 @@ var package_default = {
118
118
 
119
119
  // src/program.ts
120
120
  init_esm_shims();
121
- import { Effect as Effect21, Stream as Stream10 } from "effect";
121
+ import { Effect as Effect23, Stream as Stream10 } from "effect";
122
122
 
123
123
  // src/consumers/index.ts
124
124
  init_esm_shims();
@@ -2217,6 +2217,7 @@ var ANSIOutput = class {
2217
2217
  init_esm_shims();
2218
2218
 
2219
2219
  // src/consumers/tui/consumer.ts
2220
+ var CLOCK_REFRESH_INTERVAL_MS = 1e3;
2220
2221
  function formatErrorToLines2(err, lines) {
2221
2222
  if (err instanceof Error) {
2222
2223
  lines.push(` - ${err.name}: ${err.message}`);
@@ -2276,6 +2277,17 @@ function createTUIConsumer() {
2276
2277
  const inputFiber = yield* Effect3.forkDaemon(
2277
2278
  runInputLoop(stateRef, output)
2278
2279
  );
2280
+ const clockFiber = yield* Effect3.forkDaemon(
2281
+ Effect3.forever(
2282
+ Effect3.gen(function* () {
2283
+ yield* Effect3.sleep(CLOCK_REFRESH_INTERVAL_MS);
2284
+ const state = yield* Ref2.get(stateRef);
2285
+ if (state.status === "running") {
2286
+ yield* Effect3.sync(() => safeRender(state, output));
2287
+ }
2288
+ })
2289
+ )
2290
+ );
2279
2291
  const processEvents = events.pipe(
2280
2292
  Stream3.runForEach(
2281
2293
  (event) => Effect3.gen(function* () {
@@ -2327,6 +2339,7 @@ ${errorText}
2327
2339
  })
2328
2340
  );
2329
2341
  }
2342
+ yield* Fiber.interrupt(clockFiber);
2330
2343
  unsubscribeResize();
2331
2344
  cleanup();
2332
2345
  })
@@ -2335,13 +2348,15 @@ ${errorText}
2335
2348
 
2336
2349
  // src/layers/index.ts
2337
2350
  init_esm_shims();
2338
- import { Layer as Layer12 } from "effect";
2351
+ import { Layer as Layer14 } from "effect";
2339
2352
 
2340
- // src/layers/guardrails/file-system.ts
2353
+ // src/layers/git/file-system.ts
2341
2354
  init_esm_shims();
2342
- import { mkdir, readFile, writeFile } from "fs/promises";
2355
+ import { exec } from "child_process";
2356
+ import { access, mkdir, rm } from "fs/promises";
2343
2357
  import { join } from "path";
2344
- import { DateTime, Effect as Effect4, Layer } from "effect";
2358
+ import { promisify } from "util";
2359
+ import { Effect as Effect4, Layer } from "effect";
2345
2360
 
2346
2361
  // src/domain/errors.ts
2347
2362
  init_esm_shims();
@@ -2362,6 +2377,338 @@ var GuardrailsStoreError = class extends Data.TaggedError(
2362
2377
  };
2363
2378
  var OrchestratorError = class extends Data.TaggedError("OrchestratorError") {
2364
2379
  };
2380
+ var GitError = class extends Data.TaggedError("GitError") {
2381
+ };
2382
+
2383
+ // src/services/git.ts
2384
+ init_esm_shims();
2385
+ import { Context } from "effect";
2386
+ var Git = class extends Context.Tag("@ferix/Git")() {
2387
+ };
2388
+
2389
+ // src/layers/git/file-system.ts
2390
+ var execAsync = promisify(exec);
2391
+ var WORKTREES_DIR = ".ferix/worktrees";
2392
+ var BRANCH_PREFIX = "ferix";
2393
+ function getWorktreeDir(sessionId) {
2394
+ return join(process.cwd(), WORKTREES_DIR, sessionId);
2395
+ }
2396
+ function getBranchName(sessionId) {
2397
+ return `${BRANCH_PREFIX}/${sessionId}`;
2398
+ }
2399
+ function gitExec(command, cwd) {
2400
+ return Effect4.tryPromise({
2401
+ try: async () => {
2402
+ const { stdout } = await execAsync(command, { cwd });
2403
+ return stdout.trim();
2404
+ },
2405
+ catch: (error) => {
2406
+ const execError = error;
2407
+ return new GitError({
2408
+ message: execError.stderr || execError.message || String(error),
2409
+ operation: "status",
2410
+ cause: error
2411
+ });
2412
+ }
2413
+ });
2414
+ }
2415
+ function directoryExists(dirPath) {
2416
+ return Effect4.tryPromise({
2417
+ try: async () => {
2418
+ await access(dirPath);
2419
+ return true;
2420
+ },
2421
+ catch: () => new Error("Directory does not exist")
2422
+ }).pipe(Effect4.orElseSucceed(() => false));
2423
+ }
2424
+ var make = {
2425
+ createWorktree: (sessionId, baseBranch) => Effect4.gen(function* () {
2426
+ const worktreeDir = getWorktreeDir(sessionId);
2427
+ const branchName = getBranchName(sessionId);
2428
+ const worktreesBase = join(process.cwd(), WORKTREES_DIR);
2429
+ yield* Effect4.tryPromise({
2430
+ try: () => mkdir(worktreesBase, { recursive: true }),
2431
+ catch: (error) => new GitError({
2432
+ message: `Failed to create worktrees directory: ${String(error)}`,
2433
+ operation: "createWorktree",
2434
+ cause: error
2435
+ })
2436
+ });
2437
+ const exists = yield* directoryExists(worktreeDir);
2438
+ if (exists) {
2439
+ return worktreeDir;
2440
+ }
2441
+ const baseRef = baseBranch || "HEAD";
2442
+ const command = `git worktree add "${worktreeDir}" -b "${branchName}" ${baseRef}`;
2443
+ yield* gitExec(command).pipe(
2444
+ Effect4.mapError(
2445
+ (error) => new GitError({
2446
+ message: `Failed to create worktree: ${error.message}`,
2447
+ operation: "createWorktree",
2448
+ cause: error
2449
+ })
2450
+ )
2451
+ );
2452
+ return worktreeDir;
2453
+ }),
2454
+ removeWorktree: (sessionId) => Effect4.gen(function* () {
2455
+ const worktreeDir = getWorktreeDir(sessionId);
2456
+ const branchName = getBranchName(sessionId);
2457
+ const exists = yield* directoryExists(worktreeDir);
2458
+ if (!exists) {
2459
+ return;
2460
+ }
2461
+ yield* gitExec(`git worktree remove "${worktreeDir}" --force`).pipe(
2462
+ Effect4.mapError(
2463
+ (error) => new GitError({
2464
+ message: `Failed to remove worktree: ${error.message}`,
2465
+ operation: "removeWorktree",
2466
+ cause: error
2467
+ })
2468
+ ),
2469
+ // If git worktree remove fails, try manual cleanup
2470
+ Effect4.catchAll(
2471
+ () => Effect4.tryPromise({
2472
+ try: () => rm(worktreeDir, { recursive: true, force: true }),
2473
+ catch: (error) => new GitError({
2474
+ message: `Failed to remove worktree directory: ${String(error)}`,
2475
+ operation: "removeWorktree",
2476
+ cause: error
2477
+ })
2478
+ })
2479
+ )
2480
+ );
2481
+ yield* gitExec(`git branch -D "${branchName}"`).pipe(
2482
+ Effect4.catchAll(() => Effect4.succeed(void 0))
2483
+ );
2484
+ yield* gitExec("git worktree prune").pipe(
2485
+ Effect4.catchAll(() => Effect4.succeed(void 0))
2486
+ );
2487
+ }),
2488
+ getWorktreePath: (sessionId) => Effect4.gen(function* () {
2489
+ const worktreeDir = getWorktreeDir(sessionId);
2490
+ const exists = yield* directoryExists(worktreeDir);
2491
+ return exists ? worktreeDir : void 0;
2492
+ }),
2493
+ commitChanges: (sessionId, message) => Effect4.gen(function* () {
2494
+ const worktreeDir = getWorktreeDir(sessionId);
2495
+ const exists = yield* directoryExists(worktreeDir);
2496
+ if (!exists) {
2497
+ return yield* Effect4.fail(
2498
+ new GitError({
2499
+ message: `Worktree not found for session: ${sessionId}`,
2500
+ operation: "commit"
2501
+ })
2502
+ );
2503
+ }
2504
+ yield* gitExec("git add -A", worktreeDir).pipe(
2505
+ Effect4.mapError(
2506
+ (error) => new GitError({
2507
+ message: `Failed to stage changes: ${error.message}`,
2508
+ operation: "commit",
2509
+ cause: error
2510
+ })
2511
+ )
2512
+ );
2513
+ const status = yield* gitExec("git status --porcelain", worktreeDir).pipe(
2514
+ Effect4.catchAll(() => Effect4.succeed(""))
2515
+ );
2516
+ if (!status) {
2517
+ const head = yield* gitExec("git rev-parse HEAD", worktreeDir).pipe(
2518
+ Effect4.mapError(
2519
+ (error) => new GitError({
2520
+ message: `Failed to get HEAD: ${error.message}`,
2521
+ operation: "commit",
2522
+ cause: error
2523
+ })
2524
+ )
2525
+ );
2526
+ return head;
2527
+ }
2528
+ const escapedMessage = message.replace(/"/g, '\\"');
2529
+ yield* gitExec(`git commit -m "${escapedMessage}"`, worktreeDir).pipe(
2530
+ Effect4.mapError(
2531
+ (error) => new GitError({
2532
+ message: `Failed to commit: ${error.message}`,
2533
+ operation: "commit",
2534
+ cause: error
2535
+ })
2536
+ )
2537
+ );
2538
+ const hash = yield* gitExec("git rev-parse HEAD", worktreeDir).pipe(
2539
+ Effect4.mapError(
2540
+ (error) => new GitError({
2541
+ message: `Failed to get commit hash: ${error.message}`,
2542
+ operation: "commit",
2543
+ cause: error
2544
+ })
2545
+ )
2546
+ );
2547
+ return hash;
2548
+ }),
2549
+ pushBranch: (sessionId) => Effect4.gen(function* () {
2550
+ const worktreeDir = getWorktreeDir(sessionId);
2551
+ const branchName = getBranchName(sessionId);
2552
+ const exists = yield* directoryExists(worktreeDir);
2553
+ if (!exists) {
2554
+ return yield* Effect4.fail(
2555
+ new GitError({
2556
+ message: `Worktree not found for session: ${sessionId}`,
2557
+ operation: "push"
2558
+ })
2559
+ );
2560
+ }
2561
+ yield* gitExec(`git push -u origin "${branchName}"`, worktreeDir).pipe(
2562
+ Effect4.mapError(
2563
+ (error) => new GitError({
2564
+ message: `Failed to push branch: ${error.message}`,
2565
+ operation: "push",
2566
+ cause: error
2567
+ })
2568
+ )
2569
+ );
2570
+ }),
2571
+ createPR: (sessionId, title, body) => Effect4.gen(function* () {
2572
+ const worktreeDir = getWorktreeDir(sessionId);
2573
+ const exists = yield* directoryExists(worktreeDir);
2574
+ if (!exists) {
2575
+ return yield* Effect4.fail(
2576
+ new GitError({
2577
+ message: `Worktree not found for session: ${sessionId}`,
2578
+ operation: "createPR"
2579
+ })
2580
+ );
2581
+ }
2582
+ const escapedTitle = title.replace(/"/g, '\\"');
2583
+ const escapedBody = body.replace(/"/g, '\\"');
2584
+ const prUrl = yield* gitExec(
2585
+ `gh pr create --title "${escapedTitle}" --body "${escapedBody}"`,
2586
+ worktreeDir
2587
+ ).pipe(
2588
+ Effect4.mapError(
2589
+ (error) => new GitError({
2590
+ message: `Failed to create PR: ${error.message}`,
2591
+ operation: "createPR",
2592
+ cause: error
2593
+ })
2594
+ )
2595
+ );
2596
+ return prUrl;
2597
+ }),
2598
+ getBranchName
2599
+ };
2600
+ var Live = Layer.succeed(Git, make);
2601
+ var FileSystemGit = {
2602
+ Live
2603
+ };
2604
+
2605
+ // src/layers/git/memory.ts
2606
+ init_esm_shims();
2607
+ import { Effect as Effect5, Layer as Layer2, Ref as Ref3 } from "effect";
2608
+ var BRANCH_PREFIX2 = "ferix";
2609
+ function getBranchName2(sessionId) {
2610
+ return `${BRANCH_PREFIX2}/${sessionId}`;
2611
+ }
2612
+ function createMemoryGitService(stateRef, commitCounterRef) {
2613
+ return {
2614
+ createWorktree: (sessionId, _baseBranch) => Effect5.gen(function* () {
2615
+ const state = yield* Ref3.get(stateRef);
2616
+ const existing = state.get(sessionId);
2617
+ if (existing) {
2618
+ return existing.path;
2619
+ }
2620
+ const path2 = `.ferix/worktrees/${sessionId}`;
2621
+ const branch = getBranchName2(sessionId);
2622
+ const worktree = {
2623
+ path: path2,
2624
+ branch,
2625
+ commits: []
2626
+ };
2627
+ state.set(sessionId, worktree);
2628
+ yield* Ref3.set(stateRef, state);
2629
+ return path2;
2630
+ }),
2631
+ removeWorktree: (sessionId) => Effect5.gen(function* () {
2632
+ const state = yield* Ref3.get(stateRef);
2633
+ state.delete(sessionId);
2634
+ yield* Ref3.set(stateRef, state);
2635
+ }),
2636
+ getWorktreePath: (sessionId) => Effect5.gen(function* () {
2637
+ const state = yield* Ref3.get(stateRef);
2638
+ const worktree = state.get(sessionId);
2639
+ return worktree?.path;
2640
+ }),
2641
+ commitChanges: (sessionId, message) => Effect5.gen(function* () {
2642
+ const state = yield* Ref3.get(stateRef);
2643
+ const worktree = state.get(sessionId);
2644
+ if (!worktree) {
2645
+ return yield* Effect5.fail(
2646
+ new GitError({
2647
+ message: `Worktree not found for session: ${sessionId}`,
2648
+ operation: "commit"
2649
+ })
2650
+ );
2651
+ }
2652
+ const counter = yield* Ref3.updateAndGet(commitCounterRef, (n) => n + 1);
2653
+ const hash = `test-commit-${counter}`;
2654
+ const updatedWorktree = {
2655
+ ...worktree,
2656
+ commits: [...worktree.commits, `${hash}: ${message}`]
2657
+ };
2658
+ state.set(sessionId, updatedWorktree);
2659
+ yield* Ref3.set(stateRef, state);
2660
+ return hash;
2661
+ }),
2662
+ pushBranch: (sessionId) => Effect5.gen(function* () {
2663
+ const state = yield* Ref3.get(stateRef);
2664
+ const worktree = state.get(sessionId);
2665
+ if (!worktree) {
2666
+ return yield* Effect5.fail(
2667
+ new GitError({
2668
+ message: `Worktree not found for session: ${sessionId}`,
2669
+ operation: "push"
2670
+ })
2671
+ );
2672
+ }
2673
+ }),
2674
+ createPR: (sessionId, title, _body) => Effect5.gen(function* () {
2675
+ const state = yield* Ref3.get(stateRef);
2676
+ const worktree = state.get(sessionId);
2677
+ if (!worktree) {
2678
+ return yield* Effect5.fail(
2679
+ new GitError({
2680
+ message: `Worktree not found for session: ${sessionId}`,
2681
+ operation: "createPR"
2682
+ })
2683
+ );
2684
+ }
2685
+ const slug = title.toLowerCase().replace(/\s+/g, "-").slice(0, 30);
2686
+ return `https://github.com/test/repo/pull/${slug}`;
2687
+ }),
2688
+ getBranchName: getBranchName2
2689
+ };
2690
+ }
2691
+ function layer() {
2692
+ return Layer2.effect(
2693
+ Git,
2694
+ Effect5.gen(function* () {
2695
+ const stateRef = yield* Ref3.make(/* @__PURE__ */ new Map());
2696
+ const commitCounterRef = yield* Ref3.make(0);
2697
+ return createMemoryGitService(stateRef, commitCounterRef);
2698
+ })
2699
+ );
2700
+ }
2701
+ var Live2 = layer();
2702
+ var MemoryGit = {
2703
+ Live: Live2,
2704
+ layer
2705
+ };
2706
+
2707
+ // src/layers/guardrails/file-system.ts
2708
+ init_esm_shims();
2709
+ import { mkdir as mkdir2, readFile, writeFile } from "fs/promises";
2710
+ import { join as join2 } from "path";
2711
+ import { DateTime, Effect as Effect6, Layer as Layer3 } from "effect";
2365
2712
 
2366
2713
  // src/domain/index.ts
2367
2714
  init_esm_shims();
@@ -2649,6 +2996,16 @@ var ProgressUpdatedEventSchema = taggedEvent("ProgressUpdated", {
2649
2996
  action: S4.Literal("started", "completed", "failed", "learning"),
2650
2997
  timestamp: S4.Number
2651
2998
  });
2999
+ var WorktreeCreatedEventSchema = taggedEvent("WorktreeCreated", {
3000
+ sessionId: S4.String,
3001
+ worktreePath: S4.String,
3002
+ branchName: S4.String,
3003
+ timestamp: S4.Number
3004
+ });
3005
+ var WorktreeRemovedEventSchema = taggedEvent("WorktreeRemoved", {
3006
+ sessionId: S4.String,
3007
+ timestamp: S4.Number
3008
+ });
2652
3009
  var DomainEventSchema = S4.Union(
2653
3010
  LoopStartedEventSchema,
2654
3011
  LoopCompletedEventSchema,
@@ -2678,7 +3035,9 @@ var DomainEventSchema = S4.Union(
2678
3035
  PlanUpdateFailedEventSchema,
2679
3036
  LearningRecordedEventSchema,
2680
3037
  GuardrailAddedEventSchema,
2681
- ProgressUpdatedEventSchema
3038
+ ProgressUpdatedEventSchema,
3039
+ WorktreeCreatedEventSchema,
3040
+ WorktreeRemovedEventSchema
2682
3041
  );
2683
3042
  var DomainEventUtils = {
2684
3043
  isLLMEvent: (e) => e._tag.startsWith("LLM"),
@@ -2806,7 +3165,9 @@ var SessionSchema = S10.Struct({
2806
3165
  status: SessionStatusSchema,
2807
3166
  originalTask: S10.String,
2808
3167
  completedTasks: S10.Array(S10.String),
2809
- currentTaskId: S10.optional(S10.String)
3168
+ currentTaskId: S10.optional(S10.String),
3169
+ worktreePath: S10.optional(S10.String),
3170
+ branchName: S10.optional(S10.String)
2810
3171
  });
2811
3172
  var decodeSession = S10.decodeUnknown(SessionSchema);
2812
3173
 
@@ -3054,34 +3415,34 @@ var TUIStateSchema = S13.Struct({
3054
3415
 
3055
3416
  // src/services/guardrails-store.ts
3056
3417
  init_esm_shims();
3057
- import { Context } from "effect";
3058
- var GuardrailsStore = class extends Context.Tag("@ferix/GuardrailsStore")() {
3418
+ import { Context as Context2 } from "effect";
3419
+ var GuardrailsStore = class extends Context2.Tag("@ferix/GuardrailsStore")() {
3059
3420
  };
3060
3421
 
3061
3422
  // src/layers/guardrails/file-system.ts
3062
3423
  var PLANS_DIR = ".ferix/plans";
3063
3424
  function ensureDir(dirPath) {
3064
- return Effect4.tryPromise({
3065
- try: () => mkdir(dirPath, { recursive: true }),
3425
+ return Effect6.tryPromise({
3426
+ try: () => mkdir2(dirPath, { recursive: true }),
3066
3427
  catch: (error) => new GuardrailsStoreError({
3067
3428
  message: `Failed to create directory: ${dirPath}`,
3068
3429
  operation: "add",
3069
3430
  cause: error
3070
3431
  })
3071
- }).pipe(Effect4.asVoid);
3432
+ }).pipe(Effect6.asVoid);
3072
3433
  }
3073
3434
  function getSessionDir(sessionId) {
3074
- return join(process.cwd(), PLANS_DIR, sessionId);
3435
+ return join2(process.cwd(), PLANS_DIR, sessionId);
3075
3436
  }
3076
3437
  function getGuardrailsPath(sessionId) {
3077
- return join(getSessionDir(sessionId), "guardrails.json");
3438
+ return join2(getSessionDir(sessionId), "guardrails.json");
3078
3439
  }
3079
3440
  function serializeGuardrails(guardrails) {
3080
3441
  return JSON.stringify(guardrails, null, 2);
3081
3442
  }
3082
3443
  function deserializeGuardrails(json) {
3083
- return Effect4.gen(function* () {
3084
- const parsed = yield* Effect4.try({
3444
+ return Effect6.gen(function* () {
3445
+ const parsed = yield* Effect6.try({
3085
3446
  try: () => JSON.parse(json),
3086
3447
  catch: (error) => new GuardrailsStoreError({
3087
3448
  message: `Invalid JSON in guardrails file: ${String(error)}`,
@@ -3090,7 +3451,7 @@ function deserializeGuardrails(json) {
3090
3451
  })
3091
3452
  });
3092
3453
  const validated = yield* decodeGuardrailsFile(parsed).pipe(
3093
- Effect4.mapError(
3454
+ Effect6.mapError(
3094
3455
  (error) => new GuardrailsStoreError({
3095
3456
  message: `Guardrails validation failed: ${String(error)}`,
3096
3457
  operation: "load",
@@ -3108,12 +3469,12 @@ function createEmptyGuardrails(sessionId, createdAt) {
3108
3469
  guardrails: []
3109
3470
  };
3110
3471
  }
3111
- var make = {
3112
- add: (sessionId, guardrail) => Effect4.gen(function* () {
3472
+ var make2 = {
3473
+ add: (sessionId, guardrail) => Effect6.gen(function* () {
3113
3474
  const sessionDir = getSessionDir(sessionId);
3114
3475
  yield* ensureDir(sessionDir);
3115
3476
  const guardrailsPath = getGuardrailsPath(sessionId);
3116
- const existing = yield* Effect4.tryPromise({
3477
+ const existing = yield* Effect6.tryPromise({
3117
3478
  try: async () => {
3118
3479
  try {
3119
3480
  const content = await readFile(guardrailsPath, "utf-8");
@@ -3131,7 +3492,7 @@ var make = {
3131
3492
  let guardrails;
3132
3493
  if (existing) {
3133
3494
  guardrails = yield* deserializeGuardrails(existing).pipe(
3134
- Effect4.mapError(
3495
+ Effect6.mapError(
3135
3496
  (err) => new GuardrailsStoreError({
3136
3497
  message: err.message,
3137
3498
  operation: "add",
@@ -3147,7 +3508,7 @@ var make = {
3147
3508
  ...guardrails,
3148
3509
  guardrails: [...guardrails.guardrails, guardrail]
3149
3510
  };
3150
- yield* Effect4.tryPromise({
3511
+ yield* Effect6.tryPromise({
3151
3512
  try: () => writeFile(
3152
3513
  guardrailsPath,
3153
3514
  serializeGuardrails(updatedGuardrails),
@@ -3160,9 +3521,9 @@ var make = {
3160
3521
  })
3161
3522
  });
3162
3523
  }),
3163
- load: (sessionId) => Effect4.gen(function* () {
3524
+ load: (sessionId) => Effect6.gen(function* () {
3164
3525
  const guardrailsPath = getGuardrailsPath(sessionId);
3165
- const content = yield* Effect4.tryPromise({
3526
+ const content = yield* Effect6.tryPromise({
3166
3527
  try: async () => {
3167
3528
  try {
3168
3529
  return await readFile(guardrailsPath, "utf-8");
@@ -3182,23 +3543,23 @@ var make = {
3182
3543
  }
3183
3544
  return yield* deserializeGuardrails(content);
3184
3545
  }),
3185
- getActive: (sessionId) => Effect4.gen(function* () {
3186
- const guardrails = yield* make.load(sessionId);
3546
+ getActive: (sessionId) => Effect6.gen(function* () {
3547
+ const guardrails = yield* make2.load(sessionId);
3187
3548
  return guardrails.guardrails;
3188
3549
  })
3189
3550
  };
3190
- var Live = Layer.succeed(GuardrailsStore, make);
3551
+ var Live3 = Layer3.succeed(GuardrailsStore, make2);
3191
3552
  var FileSystemGuardrails = {
3192
- Live
3553
+ Live: Live3
3193
3554
  };
3194
3555
 
3195
3556
  // src/layers/guardrails/memory.ts
3196
3557
  init_esm_shims();
3197
- import { DateTime as DateTime2, Effect as Effect5, Layer as Layer2, Ref as Ref3 } from "effect";
3558
+ import { DateTime as DateTime2, Effect as Effect7, Layer as Layer4, Ref as Ref4 } from "effect";
3198
3559
  function createMemoryGuardrailsStore(stateRef) {
3199
3560
  return {
3200
- add: (sessionId, guardrail) => Effect5.gen(function* () {
3201
- const state = yield* Ref3.get(stateRef);
3561
+ add: (sessionId, guardrail) => Effect7.gen(function* () {
3562
+ const state = yield* Ref4.get(stateRef);
3202
3563
  let guardrails = state.get(sessionId);
3203
3564
  if (!guardrails) {
3204
3565
  const now = yield* DateTime2.now;
@@ -3213,10 +3574,10 @@ function createMemoryGuardrailsStore(stateRef) {
3213
3574
  guardrails: [...guardrails.guardrails, guardrail]
3214
3575
  };
3215
3576
  state.set(sessionId, updatedGuardrails);
3216
- yield* Ref3.set(stateRef, state);
3577
+ yield* Ref4.set(stateRef, state);
3217
3578
  }),
3218
- load: (sessionId) => Effect5.gen(function* () {
3219
- const state = yield* Ref3.get(stateRef);
3579
+ load: (sessionId) => Effect7.gen(function* () {
3580
+ const state = yield* Ref4.get(stateRef);
3220
3581
  const guardrails = state.get(sessionId);
3221
3582
  if (!guardrails) {
3222
3583
  const now = yield* DateTime2.now;
@@ -3228,8 +3589,8 @@ function createMemoryGuardrailsStore(stateRef) {
3228
3589
  }
3229
3590
  return guardrails;
3230
3591
  }),
3231
- getActive: (sessionId) => Effect5.gen(function* () {
3232
- const state = yield* Ref3.get(stateRef);
3592
+ getActive: (sessionId) => Effect7.gen(function* () {
3593
+ const state = yield* Ref4.get(stateRef);
3233
3594
  const guardrails = state.get(sessionId);
3234
3595
  if (!guardrails) {
3235
3596
  return [];
@@ -3238,36 +3599,36 @@ function createMemoryGuardrailsStore(stateRef) {
3238
3599
  })
3239
3600
  };
3240
3601
  }
3241
- function layer() {
3242
- return Layer2.effect(
3602
+ function layer2() {
3603
+ return Layer4.effect(
3243
3604
  GuardrailsStore,
3244
- Effect5.gen(function* () {
3245
- const stateRef = yield* Ref3.make(/* @__PURE__ */ new Map());
3605
+ Effect7.gen(function* () {
3606
+ const stateRef = yield* Ref4.make(/* @__PURE__ */ new Map());
3246
3607
  return createMemoryGuardrailsStore(stateRef);
3247
3608
  })
3248
3609
  );
3249
3610
  }
3250
- var Live2 = layer();
3611
+ var Live4 = layer2();
3251
3612
  var MemoryGuardrails = {
3252
- Live: Live2,
3253
- layer
3613
+ Live: Live4,
3614
+ layer: layer2
3254
3615
  };
3255
3616
 
3256
3617
  // src/layers/llm/claude-cli.ts
3257
3618
  init_esm_shims();
3258
3619
  import { spawn } from "child_process";
3259
- import { Effect as Effect7, Layer as Layer3, Stream as Stream5 } from "effect";
3620
+ import { Effect as Effect9, Layer as Layer5, Stream as Stream5 } from "effect";
3260
3621
 
3261
3622
  // src/services/llm.ts
3262
3623
  init_esm_shims();
3263
- import { Context as Context2 } from "effect";
3264
- var LLM = class extends Context2.Tag("@ferix/LLM")() {
3624
+ import { Context as Context3 } from "effect";
3625
+ var LLM = class extends Context3.Tag("@ferix/LLM")() {
3265
3626
  };
3266
3627
 
3267
3628
  // src/layers/llm/stream.ts
3268
3629
  init_esm_shims();
3269
3630
  import { createInterface } from "readline";
3270
- import { Effect as Effect6, Stream as Stream4 } from "effect";
3631
+ import { Effect as Effect8, Stream as Stream4 } from "effect";
3271
3632
 
3272
3633
  // src/layers/llm/parsers.ts
3273
3634
  init_esm_shims();
@@ -3393,7 +3754,7 @@ function createEventStream(child) {
3393
3754
  emit.fail(
3394
3755
  new LLMError({ message: "Failed to get stdout from child process" })
3395
3756
  );
3396
- return Effect6.void;
3757
+ return Effect8.void;
3397
3758
  }
3398
3759
  const rl = createInterface({
3399
3760
  input: stdout,
@@ -3432,17 +3793,17 @@ function createEventStream(child) {
3432
3793
  })
3433
3794
  );
3434
3795
  });
3435
- return Effect6.sync(() => {
3796
+ return Effect8.sync(() => {
3436
3797
  child.kill("SIGTERM");
3437
3798
  });
3438
3799
  });
3439
3800
  }
3440
3801
 
3441
3802
  // src/layers/llm/claude-cli.ts
3442
- var make2 = {
3443
- execute: (prompt) => {
3803
+ var make3 = {
3804
+ execute: (prompt, options) => {
3444
3805
  return Stream5.unwrap(
3445
- Effect7.sync(() => {
3806
+ Effect9.sync(() => {
3446
3807
  const child = spawn(
3447
3808
  "claude",
3448
3809
  [
@@ -3457,6 +3818,7 @@ var make2 = {
3457
3818
  ],
3458
3819
  {
3459
3820
  stdio: ["inherit", "pipe", "pipe"],
3821
+ cwd: options?.cwd,
3460
3822
  env: {
3461
3823
  ...process.env,
3462
3824
  FORCE_COLOR: "1"
@@ -3468,25 +3830,25 @@ var make2 = {
3468
3830
  );
3469
3831
  }
3470
3832
  };
3471
- var Live3 = Layer3.succeed(LLM, make2);
3833
+ var Live5 = Layer5.succeed(LLM, make3);
3472
3834
  var ClaudeCLI = {
3473
- Live: Live3
3835
+ Live: Live5
3474
3836
  };
3475
3837
 
3476
3838
  // src/layers/llm/mock.ts
3477
3839
  init_esm_shims();
3478
- import { Effect as Effect8, Layer as Layer4, Schema as S14, Stream as Stream6 } from "effect";
3840
+ import { Effect as Effect10, Layer as Layer6, Schema as S14, Stream as Stream6 } from "effect";
3479
3841
  var MockLLMConfigSchema = S14.Struct({
3480
3842
  events: S14.Array(LLMEventSchema),
3481
3843
  delayMs: S14.optional(S14.Number)
3482
3844
  });
3483
3845
  function createMockLLM(config) {
3484
3846
  return {
3485
- execute: (_prompt) => {
3847
+ execute: (_prompt, _options) => {
3486
3848
  const baseStream = Stream6.fromIterable(config.events);
3487
3849
  if (config.delayMs !== void 0 && config.delayMs > 0) {
3488
3850
  const delay = config.delayMs;
3489
- return baseStream.pipe(Stream6.tap(() => Effect8.sleep(delay)));
3851
+ return baseStream.pipe(Stream6.tap(() => Effect10.sleep(delay)));
3490
3852
  }
3491
3853
  return baseStream;
3492
3854
  }
@@ -3503,45 +3865,45 @@ var defaultMockEvents = [
3503
3865
  }
3504
3866
  ];
3505
3867
  var defaultMock = createMockLLM({ events: defaultMockEvents });
3506
- var Live4 = Layer4.succeed(LLM, defaultMock);
3507
- function layer2(config) {
3508
- return Layer4.succeed(LLM, createMockLLM(config));
3868
+ var Live6 = Layer6.succeed(LLM, defaultMock);
3869
+ function layer3(config) {
3870
+ return Layer6.succeed(LLM, createMockLLM(config));
3509
3871
  }
3510
3872
  var Mock = {
3511
- Live: Live4,
3512
- layer: layer2,
3873
+ Live: Live6,
3874
+ layer: layer3,
3513
3875
  createMockLLM
3514
3876
  };
3515
3877
 
3516
3878
  // src/layers/plan/file-system.ts
3517
3879
  init_esm_shims();
3518
- import { access, mkdir as mkdir2, readdir, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
3519
- import { join as join2 } from "path";
3520
- import { Effect as Effect9, Layer as Layer5 } from "effect";
3880
+ import { access as access2, mkdir as mkdir3, readdir, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
3881
+ import { join as join3 } from "path";
3882
+ import { Effect as Effect11, Layer as Layer7 } from "effect";
3521
3883
 
3522
3884
  // src/services/plan-store.ts
3523
3885
  init_esm_shims();
3524
- import { Context as Context3 } from "effect";
3525
- var PlanStore = class extends Context3.Tag("@ferix/PlanStore")() {
3886
+ import { Context as Context4 } from "effect";
3887
+ var PlanStore = class extends Context4.Tag("@ferix/PlanStore")() {
3526
3888
  };
3527
3889
 
3528
3890
  // src/layers/plan/file-system.ts
3529
3891
  var PLANS_DIR2 = ".ferix/plans";
3530
3892
  function ensureDir2(dirPath) {
3531
- return Effect9.tryPromise({
3532
- try: () => mkdir2(dirPath, { recursive: true }),
3893
+ return Effect11.tryPromise({
3894
+ try: () => mkdir3(dirPath, { recursive: true }),
3533
3895
  catch: (error) => new PlanStoreError({
3534
3896
  message: `Failed to create directory: ${dirPath}`,
3535
3897
  operation: "create",
3536
3898
  cause: error
3537
3899
  })
3538
- }).pipe(Effect9.asVoid);
3900
+ }).pipe(Effect11.asVoid);
3539
3901
  }
3540
3902
  function getSessionDir2(sessionId) {
3541
- return join2(process.cwd(), PLANS_DIR2, sessionId);
3903
+ return join3(process.cwd(), PLANS_DIR2, sessionId);
3542
3904
  }
3543
3905
  function getPlanPath(sessionId, planId) {
3544
- return join2(getSessionDir2(sessionId), `${planId}.json`);
3906
+ return join3(getSessionDir2(sessionId), `${planId}.json`);
3545
3907
  }
3546
3908
  function generatePlanId(taskNumber) {
3547
3909
  return PlanId(`task-${taskNumber}`);
@@ -3550,8 +3912,8 @@ function serializePlan(plan) {
3550
3912
  return JSON.stringify(plan, null, 2);
3551
3913
  }
3552
3914
  function deserializePlan(json, planId) {
3553
- return Effect9.gen(function* () {
3554
- const parsed = yield* Effect9.try({
3915
+ return Effect11.gen(function* () {
3916
+ const parsed = yield* Effect11.try({
3555
3917
  try: () => JSON.parse(json),
3556
3918
  catch: (error) => new PlanStoreError({
3557
3919
  message: `Invalid JSON in plan file: ${String(error)}`,
@@ -3560,7 +3922,7 @@ function deserializePlan(json, planId) {
3560
3922
  })
3561
3923
  });
3562
3924
  const validated = yield* decodePlanData(parsed).pipe(
3563
- Effect9.mapError(
3925
+ Effect11.mapError(
3564
3926
  (error) => new PlanStoreError({
3565
3927
  message: `Plan validation failed: ${String(error)}`,
3566
3928
  operation: "load",
@@ -3574,11 +3936,11 @@ function deserializePlan(json, planId) {
3574
3936
  };
3575
3937
  });
3576
3938
  }
3577
- var make3 = {
3578
- create: (sessionId, plan) => Effect9.gen(function* () {
3939
+ var make4 = {
3940
+ create: (sessionId, plan) => Effect11.gen(function* () {
3579
3941
  const sessionDir = getSessionDir2(sessionId);
3580
3942
  yield* ensureDir2(sessionDir);
3581
- const existingPlans = yield* Effect9.tryPromise({
3943
+ const existingPlans = yield* Effect11.tryPromise({
3582
3944
  try: async () => {
3583
3945
  try {
3584
3946
  const files = await readdir(sessionDir);
@@ -3595,7 +3957,7 @@ var make3 = {
3595
3957
  const planId = generatePlanId(existingPlans + 1);
3596
3958
  const planPath = getPlanPath(sessionId, planId);
3597
3959
  const fullPlan = { ...plan, id: planId };
3598
- yield* Effect9.tryPromise({
3960
+ yield* Effect11.tryPromise({
3599
3961
  try: () => writeFile2(planPath, serializePlan(fullPlan), "utf-8"),
3600
3962
  catch: (error) => new PlanStoreError({
3601
3963
  message: `Failed to write plan file: ${planPath}`,
@@ -3605,10 +3967,10 @@ var make3 = {
3605
3967
  });
3606
3968
  return planId;
3607
3969
  }),
3608
- load: (planId, sessionId) => Effect9.gen(function* () {
3970
+ load: (planId, sessionId) => Effect11.gen(function* () {
3609
3971
  if (sessionId) {
3610
3972
  const planPath = getPlanPath(sessionId, planId);
3611
- const content = yield* Effect9.tryPromise({
3973
+ const content = yield* Effect11.tryPromise({
3612
3974
  try: () => readFile2(planPath, "utf-8"),
3613
3975
  catch: (error) => new PlanStoreError({
3614
3976
  message: `Failed to read plan file: ${planPath}`,
@@ -3618,9 +3980,9 @@ var make3 = {
3618
3980
  });
3619
3981
  return yield* deserializePlan(content, planId);
3620
3982
  }
3621
- const sessionDirs = yield* Effect9.tryPromise({
3983
+ const sessionDirs = yield* Effect11.tryPromise({
3622
3984
  try: async () => {
3623
- const plansDir = join2(process.cwd(), PLANS_DIR2);
3985
+ const plansDir = join3(process.cwd(), PLANS_DIR2);
3624
3986
  const dirs = await readdir(plansDir);
3625
3987
  return dirs;
3626
3988
  },
@@ -3632,18 +3994,18 @@ var make3 = {
3632
3994
  });
3633
3995
  for (const sid of sessionDirs) {
3634
3996
  const planPath = getPlanPath(sid, planId);
3635
- const exists = yield* Effect9.tryPromise({
3997
+ const exists = yield* Effect11.tryPromise({
3636
3998
  try: async () => {
3637
- await access(planPath);
3999
+ await access2(planPath);
3638
4000
  return true;
3639
4001
  },
3640
4002
  catch: () => new PlanStoreError({
3641
4003
  message: "File not found",
3642
4004
  operation: "load"
3643
4005
  })
3644
- }).pipe(Effect9.orElseSucceed(() => false));
4006
+ }).pipe(Effect11.orElseSucceed(() => false));
3645
4007
  if (exists) {
3646
- const content = yield* Effect9.tryPromise({
4008
+ const content = yield* Effect11.tryPromise({
3647
4009
  try: () => readFile2(planPath, "utf-8"),
3648
4010
  catch: (error) => new PlanStoreError({
3649
4011
  message: `Failed to read plan file: ${planPath}`,
@@ -3654,16 +4016,16 @@ var make3 = {
3654
4016
  return yield* deserializePlan(content, planId);
3655
4017
  }
3656
4018
  }
3657
- return yield* Effect9.fail(
4019
+ return yield* Effect11.fail(
3658
4020
  new PlanStoreError({
3659
4021
  message: `Plan not found: ${planId}`,
3660
4022
  operation: "load"
3661
4023
  })
3662
4024
  );
3663
4025
  }),
3664
- update: (planId, plan) => Effect9.gen(function* () {
4026
+ update: (planId, plan) => Effect11.gen(function* () {
3665
4027
  const planPath = getPlanPath(plan.sessionId, planId);
3666
- yield* Effect9.tryPromise({
4028
+ yield* Effect11.tryPromise({
3667
4029
  try: () => writeFile2(planPath, serializePlan(plan), "utf-8"),
3668
4030
  catch: (error) => new PlanStoreError({
3669
4031
  message: `Failed to update plan file: ${planPath}`,
@@ -3672,9 +4034,9 @@ var make3 = {
3672
4034
  })
3673
4035
  });
3674
4036
  }),
3675
- list: (sessionId) => Effect9.gen(function* () {
4037
+ list: (sessionId) => Effect11.gen(function* () {
3676
4038
  const sessionDir = getSessionDir2(sessionId);
3677
- const files = yield* Effect9.tryPromise({
4039
+ const files = yield* Effect11.tryPromise({
3678
4040
  try: async () => {
3679
4041
  try {
3680
4042
  return await readdir(sessionDir);
@@ -3691,18 +4053,18 @@ var make3 = {
3691
4053
  return files.filter((f) => f.endsWith(".json")).map((f) => PlanId(f.replace(".json", "")));
3692
4054
  })
3693
4055
  };
3694
- var Live5 = Layer5.succeed(PlanStore, make3);
4056
+ var Live7 = Layer7.succeed(PlanStore, make4);
3695
4057
  var FileSystemPlan = {
3696
- Live: Live5
4058
+ Live: Live7
3697
4059
  };
3698
4060
 
3699
4061
  // src/layers/plan/memory.ts
3700
4062
  init_esm_shims();
3701
- import { Effect as Effect10, Layer as Layer6, Ref as Ref4 } from "effect";
4063
+ import { Effect as Effect12, Layer as Layer8, Ref as Ref5 } from "effect";
3702
4064
  function createMemoryPlanStore(stateRef) {
3703
4065
  return {
3704
- create: (sessionId, plan) => Effect10.gen(function* () {
3705
- const state = yield* Ref4.get(stateRef);
4066
+ create: (sessionId, plan) => Effect12.gen(function* () {
4067
+ const state = yield* Ref5.get(stateRef);
3706
4068
  if (!state.has(sessionId)) {
3707
4069
  state.set(sessionId, /* @__PURE__ */ new Map());
3708
4070
  }
@@ -3713,18 +4075,18 @@ function createMemoryPlanStore(stateRef) {
3713
4075
  const planId = PlanId(`task-${sessionPlans.size + 1}`);
3714
4076
  const fullPlan = { ...plan, id: planId };
3715
4077
  sessionPlans.set(planId, fullPlan);
3716
- yield* Ref4.set(stateRef, state);
4078
+ yield* Ref5.set(stateRef, state);
3717
4079
  return planId;
3718
4080
  }),
3719
- load: (planId, sessionId) => Effect10.gen(function* () {
3720
- const state = yield* Ref4.get(stateRef);
4081
+ load: (planId, sessionId) => Effect12.gen(function* () {
4082
+ const state = yield* Ref5.get(stateRef);
3721
4083
  if (sessionId) {
3722
4084
  const sessionPlans = state.get(sessionId);
3723
4085
  const plan = sessionPlans?.get(planId);
3724
4086
  if (plan) {
3725
4087
  return plan;
3726
4088
  }
3727
- return yield* Effect10.fail(
4089
+ return yield* Effect12.fail(
3728
4090
  new PlanStoreError({
3729
4091
  message: `Plan not found: ${planId}`,
3730
4092
  operation: "load"
@@ -3737,18 +4099,18 @@ function createMemoryPlanStore(stateRef) {
3737
4099
  return plan;
3738
4100
  }
3739
4101
  }
3740
- return yield* Effect10.fail(
4102
+ return yield* Effect12.fail(
3741
4103
  new PlanStoreError({
3742
4104
  message: `Plan not found: ${planId}`,
3743
4105
  operation: "load"
3744
4106
  })
3745
4107
  );
3746
4108
  }),
3747
- update: (planId, plan) => Effect10.gen(function* () {
3748
- const state = yield* Ref4.get(stateRef);
4109
+ update: (planId, plan) => Effect12.gen(function* () {
4110
+ const state = yield* Ref5.get(stateRef);
3749
4111
  const sessionPlans = state.get(plan.sessionId);
3750
4112
  if (!sessionPlans) {
3751
- return yield* Effect10.fail(
4113
+ return yield* Effect12.fail(
3752
4114
  new PlanStoreError({
3753
4115
  message: `Session not found: ${plan.sessionId}`,
3754
4116
  operation: "update"
@@ -3756,10 +4118,10 @@ function createMemoryPlanStore(stateRef) {
3756
4118
  );
3757
4119
  }
3758
4120
  sessionPlans.set(planId, plan);
3759
- yield* Ref4.set(stateRef, state);
4121
+ yield* Ref5.set(stateRef, state);
3760
4122
  }),
3761
- list: (sessionId) => Effect10.gen(function* () {
3762
- const state = yield* Ref4.get(stateRef);
4123
+ list: (sessionId) => Effect12.gen(function* () {
4124
+ const state = yield* Ref5.get(stateRef);
3763
4125
  const sessionPlans = state.get(sessionId);
3764
4126
  if (!sessionPlans) {
3765
4127
  return [];
@@ -3768,57 +4130,57 @@ function createMemoryPlanStore(stateRef) {
3768
4130
  })
3769
4131
  };
3770
4132
  }
3771
- function layer3() {
3772
- return Layer6.effect(
4133
+ function layer4() {
4134
+ return Layer8.effect(
3773
4135
  PlanStore,
3774
- Effect10.gen(function* () {
3775
- const stateRef = yield* Ref4.make(/* @__PURE__ */ new Map());
4136
+ Effect12.gen(function* () {
4137
+ const stateRef = yield* Ref5.make(/* @__PURE__ */ new Map());
3776
4138
  return createMemoryPlanStore(stateRef);
3777
4139
  })
3778
4140
  );
3779
4141
  }
3780
- var Live6 = layer3();
4142
+ var Live8 = layer4();
3781
4143
  var MemoryPlan = {
3782
- Live: Live6,
3783
- layer: layer3
4144
+ Live: Live8,
4145
+ layer: layer4
3784
4146
  };
3785
4147
 
3786
4148
  // src/layers/progress/file-system.ts
3787
4149
  init_esm_shims();
3788
- import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
3789
- import { join as join3 } from "path";
3790
- import { DateTime as DateTime3, Effect as Effect11, Layer as Layer7 } from "effect";
4150
+ import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
4151
+ import { join as join4 } from "path";
4152
+ import { DateTime as DateTime3, Effect as Effect13, Layer as Layer9 } from "effect";
3791
4153
 
3792
4154
  // src/services/progress-store.ts
3793
4155
  init_esm_shims();
3794
- import { Context as Context4 } from "effect";
3795
- var ProgressStore = class extends Context4.Tag("@ferix/ProgressStore")() {
4156
+ import { Context as Context5 } from "effect";
4157
+ var ProgressStore = class extends Context5.Tag("@ferix/ProgressStore")() {
3796
4158
  };
3797
4159
 
3798
4160
  // src/layers/progress/file-system.ts
3799
4161
  var PLANS_DIR3 = ".ferix/plans";
3800
4162
  function ensureDir3(dirPath) {
3801
- return Effect11.tryPromise({
3802
- try: () => mkdir3(dirPath, { recursive: true }),
4163
+ return Effect13.tryPromise({
4164
+ try: () => mkdir4(dirPath, { recursive: true }),
3803
4165
  catch: (error) => new ProgressStoreError({
3804
4166
  message: `Failed to create directory: ${dirPath}`,
3805
4167
  operation: "append",
3806
4168
  cause: error
3807
4169
  })
3808
- }).pipe(Effect11.asVoid);
4170
+ }).pipe(Effect13.asVoid);
3809
4171
  }
3810
4172
  function getSessionDir3(sessionId) {
3811
- return join3(process.cwd(), PLANS_DIR3, sessionId);
4173
+ return join4(process.cwd(), PLANS_DIR3, sessionId);
3812
4174
  }
3813
4175
  function getProgressPath(sessionId) {
3814
- return join3(getSessionDir3(sessionId), "progress.json");
4176
+ return join4(getSessionDir3(sessionId), "progress.json");
3815
4177
  }
3816
4178
  function serializeProgress(progress) {
3817
4179
  return JSON.stringify(progress, null, 2);
3818
4180
  }
3819
4181
  function deserializeProgress(json) {
3820
- return Effect11.gen(function* () {
3821
- const parsed = yield* Effect11.try({
4182
+ return Effect13.gen(function* () {
4183
+ const parsed = yield* Effect13.try({
3822
4184
  try: () => JSON.parse(json),
3823
4185
  catch: (error) => new ProgressStoreError({
3824
4186
  message: `Invalid JSON in progress file: ${String(error)}`,
@@ -3827,7 +4189,7 @@ function deserializeProgress(json) {
3827
4189
  })
3828
4190
  });
3829
4191
  const validated = yield* decodeProgressFile(parsed).pipe(
3830
- Effect11.mapError(
4192
+ Effect13.mapError(
3831
4193
  (error) => new ProgressStoreError({
3832
4194
  message: `Progress validation failed: ${String(error)}`,
3833
4195
  operation: "load",
@@ -3845,12 +4207,12 @@ function createEmptyProgress(sessionId, createdAt) {
3845
4207
  entries: []
3846
4208
  };
3847
4209
  }
3848
- var make4 = {
3849
- append: (sessionId, entry) => Effect11.gen(function* () {
4210
+ var make5 = {
4211
+ append: (sessionId, entry) => Effect13.gen(function* () {
3850
4212
  const sessionDir = getSessionDir3(sessionId);
3851
4213
  yield* ensureDir3(sessionDir);
3852
4214
  const progressPath = getProgressPath(sessionId);
3853
- const existing = yield* Effect11.tryPromise({
4215
+ const existing = yield* Effect13.tryPromise({
3854
4216
  try: async () => {
3855
4217
  try {
3856
4218
  const content = await readFile3(progressPath, "utf-8");
@@ -3868,7 +4230,7 @@ var make4 = {
3868
4230
  let progress;
3869
4231
  if (existing) {
3870
4232
  progress = yield* deserializeProgress(existing).pipe(
3871
- Effect11.mapError(
4233
+ Effect13.mapError(
3872
4234
  (err) => new ProgressStoreError({
3873
4235
  message: err.message,
3874
4236
  operation: "append",
@@ -3884,7 +4246,7 @@ var make4 = {
3884
4246
  ...progress,
3885
4247
  entries: [...progress.entries, entry]
3886
4248
  };
3887
- yield* Effect11.tryPromise({
4249
+ yield* Effect13.tryPromise({
3888
4250
  try: () => writeFile3(progressPath, serializeProgress(updatedProgress), "utf-8"),
3889
4251
  catch: (error) => new ProgressStoreError({
3890
4252
  message: `Failed to write progress file: ${progressPath}`,
@@ -3893,9 +4255,9 @@ var make4 = {
3893
4255
  })
3894
4256
  });
3895
4257
  }),
3896
- load: (sessionId) => Effect11.gen(function* () {
4258
+ load: (sessionId) => Effect13.gen(function* () {
3897
4259
  const progressPath = getProgressPath(sessionId);
3898
- const content = yield* Effect11.tryPromise({
4260
+ const content = yield* Effect13.tryPromise({
3899
4261
  try: async () => {
3900
4262
  try {
3901
4263
  return await readFile3(progressPath, "utf-8");
@@ -3915,24 +4277,24 @@ var make4 = {
3915
4277
  }
3916
4278
  return yield* deserializeProgress(content);
3917
4279
  }),
3918
- getRecent: (sessionId, count) => Effect11.gen(function* () {
3919
- const progress = yield* make4.load(sessionId);
4280
+ getRecent: (sessionId, count) => Effect13.gen(function* () {
4281
+ const progress = yield* make5.load(sessionId);
3920
4282
  const entries = progress.entries;
3921
4283
  return entries.slice(-count);
3922
4284
  })
3923
4285
  };
3924
- var Live7 = Layer7.succeed(ProgressStore, make4);
4286
+ var Live9 = Layer9.succeed(ProgressStore, make5);
3925
4287
  var FileSystemProgress = {
3926
- Live: Live7
4288
+ Live: Live9
3927
4289
  };
3928
4290
 
3929
4291
  // src/layers/progress/memory.ts
3930
4292
  init_esm_shims();
3931
- import { DateTime as DateTime4, Effect as Effect12, Layer as Layer8, Ref as Ref5 } from "effect";
4293
+ import { DateTime as DateTime4, Effect as Effect14, Layer as Layer10, Ref as Ref6 } from "effect";
3932
4294
  function createMemoryProgressStore(stateRef) {
3933
4295
  return {
3934
- append: (sessionId, entry) => Effect12.gen(function* () {
3935
- const state = yield* Ref5.get(stateRef);
4296
+ append: (sessionId, entry) => Effect14.gen(function* () {
4297
+ const state = yield* Ref6.get(stateRef);
3936
4298
  let progress = state.get(sessionId);
3937
4299
  if (!progress) {
3938
4300
  const now = yield* DateTime4.now;
@@ -3947,10 +4309,10 @@ function createMemoryProgressStore(stateRef) {
3947
4309
  entries: [...progress.entries, entry]
3948
4310
  };
3949
4311
  state.set(sessionId, updatedProgress);
3950
- yield* Ref5.set(stateRef, state);
4312
+ yield* Ref6.set(stateRef, state);
3951
4313
  }),
3952
- load: (sessionId) => Effect12.gen(function* () {
3953
- const state = yield* Ref5.get(stateRef);
4314
+ load: (sessionId) => Effect14.gen(function* () {
4315
+ const state = yield* Ref6.get(stateRef);
3954
4316
  const progress = state.get(sessionId);
3955
4317
  if (!progress) {
3956
4318
  const now = yield* DateTime4.now;
@@ -3962,8 +4324,8 @@ function createMemoryProgressStore(stateRef) {
3962
4324
  }
3963
4325
  return progress;
3964
4326
  }),
3965
- getRecent: (sessionId, count) => Effect12.gen(function* () {
3966
- const state = yield* Ref5.get(stateRef);
4327
+ getRecent: (sessionId, count) => Effect14.gen(function* () {
4328
+ const state = yield* Ref6.get(stateRef);
3967
4329
  const progress = state.get(sessionId);
3968
4330
  if (!progress) {
3969
4331
  return [];
@@ -3972,32 +4334,32 @@ function createMemoryProgressStore(stateRef) {
3972
4334
  })
3973
4335
  };
3974
4336
  }
3975
- function layer4() {
3976
- return Layer8.effect(
4337
+ function layer5() {
4338
+ return Layer10.effect(
3977
4339
  ProgressStore,
3978
- Effect12.gen(function* () {
3979
- const stateRef = yield* Ref5.make(/* @__PURE__ */ new Map());
4340
+ Effect14.gen(function* () {
4341
+ const stateRef = yield* Ref6.make(/* @__PURE__ */ new Map());
3980
4342
  return createMemoryProgressStore(stateRef);
3981
4343
  })
3982
4344
  );
3983
4345
  }
3984
- var Live8 = layer4();
4346
+ var Live10 = layer5();
3985
4347
  var MemoryProgress = {
3986
- Live: Live8,
3987
- layer: layer4
4348
+ Live: Live10,
4349
+ layer: layer5
3988
4350
  };
3989
4351
 
3990
4352
  // src/layers/session/file-system.ts
3991
4353
  init_esm_shims();
3992
- import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
3993
- import { join as join4 } from "path";
3994
- import { DateTime as DateTime5, Effect as Effect13, Layer as Layer9 } from "effect";
4354
+ import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
4355
+ import { join as join5 } from "path";
4356
+ import { DateTime as DateTime5, Effect as Effect15, Layer as Layer11 } from "effect";
3995
4357
  import { humanId } from "human-id";
3996
4358
 
3997
4359
  // src/services/session-store.ts
3998
4360
  init_esm_shims();
3999
- import { Context as Context5 } from "effect";
4000
- var SessionStore = class extends Context5.Tag("@ferix/SessionStore")() {
4361
+ import { Context as Context6 } from "effect";
4362
+ var SessionStore = class extends Context6.Tag("@ferix/SessionStore")() {
4001
4363
  };
4002
4364
 
4003
4365
  // src/layers/session/file-system.ts
@@ -4007,24 +4369,24 @@ function generateSessionId(timestampMs) {
4007
4369
  return `${id}-${timestampMs}`;
4008
4370
  }
4009
4371
  function ensureDir4(dirPath) {
4010
- return Effect13.tryPromise({
4011
- try: () => mkdir4(dirPath, { recursive: true }),
4372
+ return Effect15.tryPromise({
4373
+ try: () => mkdir5(dirPath, { recursive: true }),
4012
4374
  catch: (error) => new SessionStoreError({
4013
4375
  message: `Failed to create directory: ${dirPath}`,
4014
4376
  operation: "create",
4015
4377
  cause: error
4016
4378
  })
4017
- }).pipe(Effect13.asVoid);
4379
+ }).pipe(Effect15.asVoid);
4018
4380
  }
4019
4381
  function getSessionPath(sessionId) {
4020
- return join4(process.cwd(), SESSIONS_DIR, `${sessionId}.json`);
4382
+ return join5(process.cwd(), SESSIONS_DIR, `${sessionId}.json`);
4021
4383
  }
4022
4384
  function serializeSession(session) {
4023
4385
  return JSON.stringify(session, null, 2);
4024
4386
  }
4025
4387
  function deserializeSession(json) {
4026
- return Effect13.gen(function* () {
4027
- const parsed = yield* Effect13.try({
4388
+ return Effect15.gen(function* () {
4389
+ const parsed = yield* Effect15.try({
4028
4390
  try: () => JSON.parse(json),
4029
4391
  catch: (error) => new SessionStoreError({
4030
4392
  message: `Invalid JSON in session file: ${String(error)}`,
@@ -4033,7 +4395,7 @@ function deserializeSession(json) {
4033
4395
  })
4034
4396
  });
4035
4397
  const validated = yield* decodeSession(parsed).pipe(
4036
- Effect13.mapError(
4398
+ Effect15.mapError(
4037
4399
  (error) => new SessionStoreError({
4038
4400
  message: `Session validation failed: ${String(error)}`,
4039
4401
  operation: "get",
@@ -4044,9 +4406,9 @@ function deserializeSession(json) {
4044
4406
  return validated;
4045
4407
  });
4046
4408
  }
4047
- var make5 = {
4048
- create: (originalTask) => Effect13.gen(function* () {
4049
- const sessionsDir = join4(process.cwd(), SESSIONS_DIR);
4409
+ var make6 = {
4410
+ create: (originalTask) => Effect15.gen(function* () {
4411
+ const sessionsDir = join5(process.cwd(), SESSIONS_DIR);
4050
4412
  yield* ensureDir4(sessionsDir);
4051
4413
  const now = yield* DateTime5.now;
4052
4414
  const timestampMs = DateTime5.toEpochMillis(now);
@@ -4059,7 +4421,7 @@ var make5 = {
4059
4421
  completedTasks: []
4060
4422
  };
4061
4423
  const sessionPath = getSessionPath(sessionId);
4062
- yield* Effect13.tryPromise({
4424
+ yield* Effect15.tryPromise({
4063
4425
  try: () => writeFile4(sessionPath, serializeSession(session), "utf-8"),
4064
4426
  catch: (error) => new SessionStoreError({
4065
4427
  message: `Failed to write session file: ${sessionPath}`,
@@ -4069,9 +4431,9 @@ var make5 = {
4069
4431
  });
4070
4432
  return session;
4071
4433
  }),
4072
- get: (sessionId) => Effect13.gen(function* () {
4434
+ get: (sessionId) => Effect15.gen(function* () {
4073
4435
  const sessionPath = getSessionPath(sessionId);
4074
- const content = yield* Effect13.tryPromise({
4436
+ const content = yield* Effect15.tryPromise({
4075
4437
  try: () => readFile4(sessionPath, "utf-8"),
4076
4438
  catch: (error) => new SessionStoreError({
4077
4439
  message: `Failed to read session file: ${sessionPath}`,
@@ -4081,9 +4443,9 @@ var make5 = {
4081
4443
  });
4082
4444
  return yield* deserializeSession(content);
4083
4445
  }),
4084
- update: (sessionId, session) => Effect13.gen(function* () {
4446
+ update: (sessionId, session) => Effect15.gen(function* () {
4085
4447
  const sessionPath = getSessionPath(sessionId);
4086
- yield* Effect13.tryPromise({
4448
+ yield* Effect15.tryPromise({
4087
4449
  try: () => writeFile4(sessionPath, serializeSession(session), "utf-8"),
4088
4450
  catch: (error) => new SessionStoreError({
4089
4451
  message: `Failed to update session file: ${sessionPath}`,
@@ -4093,19 +4455,19 @@ var make5 = {
4093
4455
  });
4094
4456
  })
4095
4457
  };
4096
- var Live9 = Layer9.succeed(SessionStore, make5);
4458
+ var Live11 = Layer11.succeed(SessionStore, make6);
4097
4459
  var FileSystemSession = {
4098
- Live: Live9
4460
+ Live: Live11
4099
4461
  };
4100
4462
 
4101
4463
  // src/layers/session/memory.ts
4102
4464
  init_esm_shims();
4103
- import { DateTime as DateTime6, Effect as Effect14, Layer as Layer10, Ref as Ref6 } from "effect";
4465
+ import { DateTime as DateTime6, Effect as Effect16, Layer as Layer12, Ref as Ref7 } from "effect";
4104
4466
  function createMemorySessionStore(stateRef, counterRef) {
4105
4467
  return {
4106
- create: (originalTask) => Effect14.gen(function* () {
4107
- const state = yield* Ref6.get(stateRef);
4108
- const counter = yield* Ref6.updateAndGet(counterRef, (n) => n + 1);
4468
+ create: (originalTask) => Effect16.gen(function* () {
4469
+ const state = yield* Ref7.get(stateRef);
4470
+ const counter = yield* Ref7.updateAndGet(counterRef, (n) => n + 1);
4109
4471
  const sessionId = `test-session-${counter}`;
4110
4472
  const now = yield* DateTime6.now;
4111
4473
  const session = {
@@ -4116,14 +4478,14 @@ function createMemorySessionStore(stateRef, counterRef) {
4116
4478
  completedTasks: []
4117
4479
  };
4118
4480
  state.set(sessionId, session);
4119
- yield* Ref6.set(stateRef, state);
4481
+ yield* Ref7.set(stateRef, state);
4120
4482
  return session;
4121
4483
  }),
4122
- get: (sessionId) => Effect14.gen(function* () {
4123
- const state = yield* Ref6.get(stateRef);
4484
+ get: (sessionId) => Effect16.gen(function* () {
4485
+ const state = yield* Ref7.get(stateRef);
4124
4486
  const session = state.get(sessionId);
4125
4487
  if (!session) {
4126
- return yield* Effect14.fail(
4488
+ return yield* Effect16.fail(
4127
4489
  new SessionStoreError({
4128
4490
  message: `Session not found: ${sessionId}`,
4129
4491
  operation: "get"
@@ -4132,10 +4494,10 @@ function createMemorySessionStore(stateRef, counterRef) {
4132
4494
  }
4133
4495
  return session;
4134
4496
  }),
4135
- update: (sessionId, session) => Effect14.gen(function* () {
4136
- const state = yield* Ref6.get(stateRef);
4497
+ update: (sessionId, session) => Effect16.gen(function* () {
4498
+ const state = yield* Ref7.get(stateRef);
4137
4499
  if (!state.has(sessionId)) {
4138
- return yield* Effect14.fail(
4500
+ return yield* Effect16.fail(
4139
4501
  new SessionStoreError({
4140
4502
  message: `Session not found: ${sessionId}`,
4141
4503
  operation: "update"
@@ -4143,34 +4505,34 @@ function createMemorySessionStore(stateRef, counterRef) {
4143
4505
  );
4144
4506
  }
4145
4507
  state.set(sessionId, session);
4146
- yield* Ref6.set(stateRef, state);
4508
+ yield* Ref7.set(stateRef, state);
4147
4509
  })
4148
4510
  };
4149
4511
  }
4150
- function layer5() {
4151
- return Layer10.effect(
4512
+ function layer6() {
4513
+ return Layer12.effect(
4152
4514
  SessionStore,
4153
- Effect14.gen(function* () {
4154
- const stateRef = yield* Ref6.make(/* @__PURE__ */ new Map());
4155
- const counterRef = yield* Ref6.make(0);
4515
+ Effect16.gen(function* () {
4516
+ const stateRef = yield* Ref7.make(/* @__PURE__ */ new Map());
4517
+ const counterRef = yield* Ref7.make(0);
4156
4518
  return createMemorySessionStore(stateRef, counterRef);
4157
4519
  })
4158
4520
  );
4159
4521
  }
4160
- var Live10 = layer5();
4522
+ var Live12 = layer6();
4161
4523
  var MemorySession = {
4162
- Live: Live10,
4163
- layer: layer5
4524
+ Live: Live12,
4525
+ layer: layer6
4164
4526
  };
4165
4527
 
4166
4528
  // src/layers/signal/ferix-parser.ts
4167
4529
  init_esm_shims();
4168
- import { Effect as Effect15, Layer as Layer11, Ref as Ref7 } from "effect";
4530
+ import { Effect as Effect17, Layer as Layer13, Ref as Ref8 } from "effect";
4169
4531
 
4170
4532
  // src/services/signal-parser.ts
4171
4533
  init_esm_shims();
4172
- import { Context as Context6 } from "effect";
4173
- var SignalParser = class extends Context6.Tag("@ferix/SignalParser")() {
4534
+ import { Context as Context7 } from "effect";
4535
+ var SignalParser = class extends Context7.Tag("@ferix/SignalParser")() {
4174
4536
  };
4175
4537
 
4176
4538
  // src/layers/signal/specs/index.ts
@@ -4675,20 +5037,20 @@ signalSpecRegistry.register(tasksDefinedSpec);
4675
5037
  // src/layers/signal/ferix-parser.ts
4676
5038
  var MAX_BUFFER_SIZE = 1024 * 1024;
4677
5039
  function createAccumulatorImpl() {
4678
- return Effect15.gen(function* () {
4679
- const chunksRef = yield* Ref7.make([]);
4680
- const emittedRef = yield* Ref7.make(/* @__PURE__ */ new Set());
4681
- const feed = (text) => Effect15.gen(function* () {
4682
- const chunks = yield* Ref7.get(chunksRef);
5040
+ return Effect17.gen(function* () {
5041
+ const chunksRef = yield* Ref8.make([]);
5042
+ const emittedRef = yield* Ref8.make(/* @__PURE__ */ new Set());
5043
+ const feed = (text) => Effect17.gen(function* () {
5044
+ const chunks = yield* Ref8.get(chunksRef);
4683
5045
  chunks.push(text);
4684
5046
  const buffer = chunks.join("");
4685
5047
  if (buffer.length > MAX_BUFFER_SIZE) {
4686
- yield* Ref7.set(chunksRef, [
5048
+ yield* Ref8.set(chunksRef, [
4687
5049
  buffer.slice(buffer.length - MAX_BUFFER_SIZE)
4688
5050
  ]);
4689
5051
  }
4690
5052
  const signals = signalSpecRegistry.parseAll(buffer);
4691
- const emitted = yield* Ref7.get(emittedRef);
5053
+ const emitted = yield* Ref8.get(emittedRef);
4692
5054
  const newSignals = signals.filter((signal) => {
4693
5055
  const key = signalSpecRegistry.getSignalKey(signal);
4694
5056
  if (emitted.has(key)) {
@@ -4700,61 +5062,64 @@ function createAccumulatorImpl() {
4700
5062
  if (newSignals.length > 0) {
4701
5063
  const lastEndPos = signalSpecRegistry.findLastCompleteSignalEnd(buffer);
4702
5064
  if (lastEndPos > 0 && lastEndPos < buffer.length) {
4703
- yield* Ref7.set(chunksRef, [buffer.slice(lastEndPos)]);
5065
+ yield* Ref8.set(chunksRef, [buffer.slice(lastEndPos)]);
4704
5066
  }
4705
5067
  }
4706
- yield* Ref7.set(emittedRef, emitted);
5068
+ yield* Ref8.set(emittedRef, emitted);
4707
5069
  return newSignals;
4708
5070
  });
4709
- const flush = () => Effect15.gen(function* () {
4710
- const chunks = yield* Ref7.get(chunksRef);
5071
+ const flush = () => Effect17.gen(function* () {
5072
+ const chunks = yield* Ref8.get(chunksRef);
4711
5073
  const buffer = chunks.join("");
4712
- yield* Ref7.set(chunksRef, []);
4713
- const emitted = yield* Ref7.get(emittedRef);
5074
+ yield* Ref8.set(chunksRef, []);
5075
+ const emitted = yield* Ref8.get(emittedRef);
4714
5076
  const signals = signalSpecRegistry.parseAll(buffer);
4715
5077
  const result = signals.filter(
4716
5078
  (signal) => !emitted.has(signalSpecRegistry.getSignalKey(signal))
4717
5079
  );
4718
- yield* Ref7.set(emittedRef, /* @__PURE__ */ new Set());
5080
+ yield* Ref8.set(emittedRef, /* @__PURE__ */ new Set());
4719
5081
  return result;
4720
5082
  });
4721
5083
  return { feed, flush };
4722
5084
  });
4723
5085
  }
4724
- var make6 = {
4725
- parse: (text) => Effect15.succeed(signalSpecRegistry.parseAll(text)),
5086
+ var make7 = {
5087
+ parse: (text) => Effect17.succeed(signalSpecRegistry.parseAll(text)),
4726
5088
  createAccumulator: createAccumulatorImpl
4727
5089
  };
4728
- var Live11 = Layer11.succeed(SignalParser, make6);
5090
+ var Live13 = Layer13.succeed(SignalParser, make7);
4729
5091
  var FerixParser = {
4730
- Live: Live11
5092
+ Live: Live13
4731
5093
  };
4732
5094
 
4733
5095
  // src/layers/index.ts
4734
- var ProductionLayers = Layer12.mergeAll(
5096
+ var ProductionLayers = Layer14.mergeAll(
4735
5097
  ClaudeCLI.Live,
4736
5098
  FerixParser.Live,
4737
5099
  FileSystemPlan.Live,
4738
5100
  FileSystemSession.Live,
4739
5101
  FileSystemProgress.Live,
4740
- FileSystemGuardrails.Live
5102
+ FileSystemGuardrails.Live,
5103
+ FileSystemGit.Live
4741
5104
  );
4742
- var TestLayers = Layer12.mergeAll(
5105
+ var TestLayers = Layer14.mergeAll(
4743
5106
  Mock.Live,
4744
5107
  FerixParser.Live,
4745
5108
  MemoryPlan.Live,
4746
5109
  MemorySession.Live,
4747
5110
  MemoryProgress.Live,
4748
- MemoryGuardrails.Live
5111
+ MemoryGuardrails.Live,
5112
+ MemoryGit.Live
4749
5113
  );
4750
5114
  function createTestLayers(events) {
4751
- return Layer12.mergeAll(
5115
+ return Layer14.mergeAll(
4752
5116
  Mock.layer({ events }),
4753
5117
  FerixParser.Live,
4754
5118
  MemoryPlan.layer(),
4755
5119
  MemorySession.layer(),
4756
5120
  MemoryProgress.layer(),
4757
- MemoryGuardrails.layer()
5121
+ MemoryGuardrails.layer(),
5122
+ MemoryGit.layer()
4758
5123
  );
4759
5124
  }
4760
5125
 
@@ -4763,41 +5128,41 @@ init_esm_shims();
4763
5128
 
4764
5129
  // src/orchestrator/loop.ts
4765
5130
  init_esm_shims();
4766
- import { DateTime as DateTime10, Effect as Effect20, Option, pipe as pipe3, Ref as Ref11, Stream as Stream9 } from "effect";
5131
+ import { DateTime as DateTime10, Effect as Effect22, Option, pipe as pipe3, Ref as Ref12, Stream as Stream9 } from "effect";
4767
5132
 
4768
5133
  // src/orchestrator/discovery.ts
4769
5134
  init_esm_shims();
4770
- import { DateTime as DateTime8, Effect as Effect18, pipe, Ref as Ref9, Stream as Stream7 } from "effect";
5135
+ import { DateTime as DateTime8, Effect as Effect20, pipe, Ref as Ref10, Stream as Stream7 } from "effect";
4771
5136
 
4772
5137
  // src/layers/plan/task-generation.ts
4773
5138
  init_esm_shims();
4774
- import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
4775
- import { join as join5 } from "path";
4776
- import { Effect as Effect16 } from "effect";
5139
+ import { mkdir as mkdir6, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
5140
+ import { join as join6 } from "path";
5141
+ import { Effect as Effect18 } from "effect";
4777
5142
  var PLANS_DIR4 = ".ferix/plans";
4778
5143
  function ensureDir5(dirPath) {
4779
- return Effect16.tryPromise({
4780
- try: () => mkdir5(dirPath, { recursive: true }),
5144
+ return Effect18.tryPromise({
5145
+ try: () => mkdir6(dirPath, { recursive: true }),
4781
5146
  catch: (error) => new PlanStoreError({
4782
5147
  message: `Failed to create directory: ${dirPath}`,
4783
5148
  operation: "create",
4784
5149
  cause: error
4785
5150
  })
4786
- }).pipe(Effect16.asVoid);
5151
+ }).pipe(Effect18.asVoid);
4787
5152
  }
4788
5153
  function getSessionDir4(sessionId) {
4789
- return join5(process.cwd(), PLANS_DIR4, sessionId);
5154
+ return join6(process.cwd(), PLANS_DIR4, sessionId);
4790
5155
  }
4791
5156
  function getTasksMdPath(sessionId) {
4792
- return join5(getSessionDir4(sessionId), "tasks.md");
5157
+ return join6(getSessionDir4(sessionId), "tasks.md");
4793
5158
  }
4794
5159
  function writeTasksMd(sessionId, tasks) {
4795
- return Effect16.gen(function* () {
5160
+ return Effect18.gen(function* () {
4796
5161
  const sessionDir = getSessionDir4(sessionId);
4797
5162
  yield* ensureDir5(sessionDir);
4798
5163
  const tasksMdPath = getTasksMdPath(sessionId);
4799
5164
  const content = formatTasksMd(tasks);
4800
- yield* Effect16.tryPromise({
5165
+ yield* Effect18.tryPromise({
4801
5166
  try: () => writeFile5(tasksMdPath, content, "utf-8"),
4802
5167
  catch: (error) => new PlanStoreError({
4803
5168
  message: `Failed to write tasks.md: ${tasksMdPath}`,
@@ -4979,7 +5344,7 @@ function mapSignalToDomain(signal, context) {
4979
5344
 
4980
5345
  // src/orchestrator/plan-updates.ts
4981
5346
  init_esm_shims();
4982
- import { DateTime as DateTime7, Effect as Effect17, Ref as Ref8 } from "effect";
5347
+ import { DateTime as DateTime7, Effect as Effect19, Ref as Ref9 } from "effect";
4983
5348
 
4984
5349
  // src/orchestrator/plan-updates/index.ts
4985
5350
  init_esm_shims();
@@ -5284,9 +5649,9 @@ function persistPlanUpdate(planStore, plan, operation) {
5284
5649
  tasks: plan.tasks
5285
5650
  }) : planStore.update(plan.id, plan);
5286
5651
  return storeOp.pipe(
5287
- Effect17.map(() => null),
5288
- Effect17.catchAll(
5289
- (error) => Effect17.succeed({
5652
+ Effect19.map(() => null),
5653
+ Effect19.catchAll(
5654
+ (error) => Effect19.succeed({
5290
5655
  _tag: "PlanUpdateFailed",
5291
5656
  operation,
5292
5657
  error: error.message,
@@ -5296,8 +5661,8 @@ function persistPlanUpdate(planStore, plan, operation) {
5296
5661
  );
5297
5662
  }
5298
5663
  function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessionId, originalTask) {
5299
- return Effect17.gen(function* () {
5300
- const currentPlan = yield* Ref8.get(currentPlanRef);
5664
+ return Effect19.gen(function* () {
5665
+ const currentPlan = yield* Ref9.get(currentPlanRef);
5301
5666
  const now = yield* DateTime7.now;
5302
5667
  const timestamp = DateTime7.formatIso(now);
5303
5668
  const updateResult = computePlanUpdate(signal, currentPlan, {
@@ -5309,8 +5674,8 @@ function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessi
5309
5674
  return [];
5310
5675
  }
5311
5676
  const { plan, operation, eventTag } = updateResult;
5312
- yield* Ref8.set(currentPlanRef, plan);
5313
- yield* Ref8.update(persistenceStateRef, (state) => ({
5677
+ yield* Ref9.set(currentPlanRef, plan);
5678
+ yield* Ref9.update(persistenceStateRef, (state) => ({
5314
5679
  dirty: true,
5315
5680
  pendingOperation: state.pendingOperation === "create" ? "create" : operation
5316
5681
  }));
@@ -5318,12 +5683,12 @@ function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessi
5318
5683
  });
5319
5684
  }
5320
5685
  function flushPlanPersistence(planStore, currentPlanRef, persistenceStateRef) {
5321
- return Effect17.gen(function* () {
5322
- const state = yield* Ref8.get(persistenceStateRef);
5686
+ return Effect19.gen(function* () {
5687
+ const state = yield* Ref9.get(persistenceStateRef);
5323
5688
  if (!(state.dirty && state.pendingOperation)) {
5324
5689
  return [];
5325
5690
  }
5326
- const plan = yield* Ref8.get(currentPlanRef);
5691
+ const plan = yield* Ref9.get(currentPlanRef);
5327
5692
  if (!plan) {
5328
5693
  return [];
5329
5694
  }
@@ -5336,7 +5701,7 @@ function flushPlanPersistence(planStore, currentPlanRef, persistenceStateRef) {
5336
5701
  if (failureEvent) {
5337
5702
  events.push(failureEvent);
5338
5703
  }
5339
- yield* Ref8.set(persistenceStateRef, {
5704
+ yield* Ref9.set(persistenceStateRef, {
5340
5705
  dirty: false,
5341
5706
  pendingOperation: null
5342
5707
  });
@@ -5592,12 +5957,12 @@ Begin.`);
5592
5957
 
5593
5958
  // src/orchestrator/discovery.ts
5594
5959
  function processTextSignals(signalParser, text, context) {
5595
- return Effect18.gen(function* () {
5960
+ return Effect20.gen(function* () {
5596
5961
  const events = [];
5597
5962
  const parsedSignals = [];
5598
5963
  const signals = yield* signalParser.parse(text).pipe(
5599
- Effect18.tapError(
5600
- (error) => Effect18.logDebug(
5964
+ Effect20.tapError(
5965
+ (error) => Effect20.logDebug(
5601
5966
  "Signal parsing failed, continuing with empty signals",
5602
5967
  {
5603
5968
  error: String(error),
@@ -5605,7 +5970,7 @@ function processTextSignals(signalParser, text, context) {
5605
5970
  }
5606
5971
  )
5607
5972
  ),
5608
- Effect18.orElseSucceed(() => [])
5973
+ Effect20.orElseSucceed(() => [])
5609
5974
  );
5610
5975
  for (const signal of signals) {
5611
5976
  events.push(mapSignalToDomain(signal, context));
@@ -5615,7 +5980,7 @@ function processTextSignals(signalParser, text, context) {
5615
5980
  });
5616
5981
  }
5617
5982
  function processLLMEvent(signalParser, llmEvent, context) {
5618
- return Effect18.gen(function* () {
5983
+ return Effect20.gen(function* () {
5619
5984
  const domainEvent = mapLLMEventToDomain(llmEvent, context);
5620
5985
  const events = [domainEvent];
5621
5986
  const allSignals = [];
@@ -5658,12 +6023,12 @@ function planTasksToGeneratedTasks(plan) {
5658
6023
  status: mapTaskStatus(task.status)
5659
6024
  }));
5660
6025
  }
5661
- function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, config, sessionId) {
6026
+ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, config, sessionId, worktreePath) {
5662
6027
  return Stream7.unwrap(
5663
- Effect18.gen(function* () {
6028
+ Effect20.gen(function* () {
5664
6029
  const startTimeUtc = yield* DateTime8.now;
5665
6030
  const startTime = DateTime8.toEpochMillis(startTimeUtc);
5666
- const persistenceStateRef = yield* Ref9.make({
6031
+ const persistenceStateRef = yield* Ref10.make({
5667
6032
  dirty: false,
5668
6033
  pendingOperation: null
5669
6034
  });
@@ -5677,7 +6042,7 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
5677
6042
  input: {}
5678
6043
  };
5679
6044
  const prompt = buildDiscoveryPrompt(config);
5680
- const llmStream = llm.execute(prompt).pipe(
6045
+ const llmStream = llm.execute(prompt, worktreePath ? { cwd: worktreePath } : void 0).pipe(
5681
6046
  Stream7.mapError(
5682
6047
  (e) => new OrchestratorError({
5683
6048
  message: `LLM execution failed during discovery: ${String(e)}`,
@@ -5687,7 +6052,7 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
5687
6052
  ),
5688
6053
  Stream7.flatMap(
5689
6054
  (llmEvent) => Stream7.unwrap(
5690
- Effect18.gen(function* () {
6055
+ Effect20.gen(function* () {
5691
6056
  const now = yield* DateTime8.now;
5692
6057
  const context = {
5693
6058
  timestamp: DateTime8.toEpochMillis(now)
@@ -5724,23 +6089,23 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
5724
6089
  )
5725
6090
  );
5726
6091
  const completionStream = Stream7.fromEffect(
5727
- Effect18.gen(function* () {
6092
+ Effect20.gen(function* () {
5728
6093
  const persistEvents = yield* flushPlanPersistence(
5729
6094
  planStore,
5730
6095
  currentPlanRef,
5731
6096
  persistenceStateRef
5732
6097
  );
5733
- const plan = yield* Ref9.get(currentPlanRef);
6098
+ const plan = yield* Ref10.get(currentPlanRef);
5734
6099
  const taskCount = plan?.tasks.length ?? 0;
5735
6100
  if (plan && plan.tasks.length > 0) {
5736
6101
  const generatedTasks = planTasksToGeneratedTasks(plan);
5737
6102
  yield* writeTasksMd(sessionId, generatedTasks).pipe(
5738
- Effect18.tapError(
5739
- (error) => Effect18.logDebug("Failed to write tasks.md, continuing", {
6103
+ Effect20.tapError(
6104
+ (error) => Effect20.logDebug("Failed to write tasks.md, continuing", {
5740
6105
  error: String(error)
5741
6106
  })
5742
6107
  ),
5743
- Effect18.orElseSucceed(() => void 0)
6108
+ Effect20.orElseSucceed(() => void 0)
5744
6109
  );
5745
6110
  }
5746
6111
  const endTimeUtc = yield* DateTime8.now;
@@ -5765,15 +6130,15 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
5765
6130
 
5766
6131
  // src/orchestrator/iteration.ts
5767
6132
  init_esm_shims();
5768
- import { DateTime as DateTime9, Effect as Effect19, pipe as pipe2, Ref as Ref10, Stream as Stream8 } from "effect";
6133
+ import { DateTime as DateTime9, Effect as Effect21, pipe as pipe2, Ref as Ref11, Stream as Stream8 } from "effect";
5769
6134
  function processTextSignals2(signalParser, text, context) {
5770
- return Effect19.gen(function* () {
6135
+ return Effect21.gen(function* () {
5771
6136
  const events = [];
5772
6137
  let completed = false;
5773
6138
  const parsedSignals = [];
5774
6139
  const signals = yield* signalParser.parse(text).pipe(
5775
- Effect19.tapError(
5776
- (error) => Effect19.logDebug(
6140
+ Effect21.tapError(
6141
+ (error) => Effect21.logDebug(
5777
6142
  "Signal parsing failed, continuing with empty signals",
5778
6143
  {
5779
6144
  error: String(error),
@@ -5781,7 +6146,7 @@ function processTextSignals2(signalParser, text, context) {
5781
6146
  }
5782
6147
  )
5783
6148
  ),
5784
- Effect19.orElseSucceed(() => [])
6149
+ Effect21.orElseSucceed(() => [])
5785
6150
  );
5786
6151
  for (const signal of signals) {
5787
6152
  events.push(mapSignalToDomain(signal, context));
@@ -5794,7 +6159,7 @@ function processTextSignals2(signalParser, text, context) {
5794
6159
  });
5795
6160
  }
5796
6161
  function processLLMEvent2(signalParser, llmEvent, context) {
5797
- return Effect19.gen(function* () {
6162
+ return Effect21.gen(function* () {
5798
6163
  const domainEvent = mapLLMEventToDomain(llmEvent, context);
5799
6164
  const events = [domainEvent];
5800
6165
  let completed = false;
@@ -5825,11 +6190,11 @@ function processLLMEvent2(signalParser, llmEvent, context) {
5825
6190
  return { events, completed, signals: allSignals };
5826
6191
  });
5827
6192
  }
5828
- function createIterationStream(llm, signalParser, planStore, currentPlanRef, loopCompletedRef, config, iteration, sessionId) {
6193
+ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loopCompletedRef, config, iteration, sessionId, worktreePath) {
5829
6194
  return Stream8.unwrap(
5830
- Effect19.gen(function* () {
5831
- const currentPlan = yield* Ref10.get(currentPlanRef);
5832
- const persistenceStateRef = yield* Ref10.make({
6195
+ Effect21.gen(function* () {
6196
+ const currentPlan = yield* Ref11.get(currentPlanRef);
6197
+ const persistenceStateRef = yield* Ref11.make({
5833
6198
  dirty: false,
5834
6199
  pendingOperation: null
5835
6200
  });
@@ -5837,7 +6202,10 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
5837
6202
  _tag: "IterationStarted",
5838
6203
  iteration
5839
6204
  };
5840
- const llmStream = llm.execute(buildPrompt(config, iteration, currentPlan)).pipe(
6205
+ const llmStream = llm.execute(
6206
+ buildPrompt(config, iteration, currentPlan),
6207
+ worktreePath ? { cwd: worktreePath } : void 0
6208
+ ).pipe(
5841
6209
  Stream8.mapError(
5842
6210
  (e) => new OrchestratorError({
5843
6211
  message: `LLM execution failed: ${String(e)}`,
@@ -5847,7 +6215,7 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
5847
6215
  ),
5848
6216
  Stream8.flatMap(
5849
6217
  (llmEvent) => Stream8.unwrap(
5850
- Effect19.gen(function* () {
6218
+ Effect21.gen(function* () {
5851
6219
  const now = yield* DateTime9.now;
5852
6220
  const context = {
5853
6221
  timestamp: DateTime9.toEpochMillis(now)
@@ -5869,7 +6237,7 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
5869
6237
  events.push(...planEvents);
5870
6238
  }
5871
6239
  if (result.completed) {
5872
- yield* Ref10.set(loopCompletedRef, true);
6240
+ yield* Ref11.set(loopCompletedRef, true);
5873
6241
  }
5874
6242
  return Stream8.fromIterable(events);
5875
6243
  })
@@ -5888,7 +6256,7 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
5888
6256
  )
5889
6257
  );
5890
6258
  const completionStream = Stream8.fromEffect(
5891
- Effect19.gen(function* () {
6259
+ Effect21.gen(function* () {
5892
6260
  const persistEvents = yield* flushPlanPersistence(
5893
6261
  planStore,
5894
6262
  currentPlanRef,
@@ -5913,13 +6281,14 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
5913
6281
  // src/orchestrator/loop.ts
5914
6282
  function runLoop(config) {
5915
6283
  return Stream9.unwrap(
5916
- Effect20.gen(function* () {
6284
+ Effect22.gen(function* () {
5917
6285
  const llm = yield* LLM;
5918
6286
  const signalParser = yield* SignalParser;
5919
6287
  const sessionStore = yield* SessionStore;
5920
6288
  const planStore = yield* PlanStore;
6289
+ const git = yield* Git;
5921
6290
  const session = yield* sessionStore.create(config.task).pipe(
5922
- Effect20.mapError(
6291
+ Effect22.mapError(
5923
6292
  (e) => new OrchestratorError({
5924
6293
  message: `Failed to create session: ${e.message}`,
5925
6294
  phase: "setup",
@@ -5927,10 +6296,39 @@ function runLoop(config) {
5927
6296
  })
5928
6297
  )
5929
6298
  );
6299
+ const worktreePath = yield* git.createWorktree(session.id).pipe(
6300
+ Effect22.mapError(
6301
+ (e) => new OrchestratorError({
6302
+ message: `Failed to create worktree: ${e.message}`,
6303
+ phase: "setup",
6304
+ cause: e
6305
+ })
6306
+ )
6307
+ );
6308
+ const branchName = git.getBranchName(session.id);
6309
+ yield* sessionStore.update(session.id, {
6310
+ ...session,
6311
+ worktreePath,
6312
+ branchName
6313
+ }).pipe(
6314
+ Effect22.tapError(
6315
+ (error) => Effect22.logDebug("Failed to update session with worktree info", {
6316
+ error: String(error)
6317
+ })
6318
+ ),
6319
+ Effect22.orElseSucceed(() => void 0)
6320
+ );
5930
6321
  const startTimeUtc = yield* DateTime10.now;
5931
6322
  const startTime = DateTime10.toEpochMillis(startTimeUtc);
5932
- const loopCompletedRef = yield* Ref11.make(false);
5933
- const currentPlanRef = yield* Ref11.make(void 0);
6323
+ const worktreeCreated = {
6324
+ _tag: "WorktreeCreated",
6325
+ sessionId: session.id,
6326
+ worktreePath,
6327
+ branchName,
6328
+ timestamp: startTime
6329
+ };
6330
+ const loopCompletedRef = yield* Ref12.make(false);
6331
+ const currentPlanRef = yield* Ref12.make(void 0);
5934
6332
  const maxIterations = config.maxIterations === 0 ? Number.POSITIVE_INFINITY : config.maxIterations;
5935
6333
  const loopStarted = {
5936
6334
  _tag: "LoopStarted",
@@ -5943,12 +6341,13 @@ function runLoop(config) {
5943
6341
  planStore,
5944
6342
  currentPlanRef,
5945
6343
  config,
5946
- session.id
6344
+ session.id,
6345
+ worktreePath
5947
6346
  );
5948
6347
  const iterationsStream = Stream9.unfoldEffect(
5949
6348
  1,
5950
- (iteration) => Effect20.gen(function* () {
5951
- const completed = yield* Ref11.get(loopCompletedRef);
6349
+ (iteration) => Effect22.gen(function* () {
6350
+ const completed = yield* Ref12.get(loopCompletedRef);
5952
6351
  if (completed || iteration > maxIterations) {
5953
6352
  return Option.none();
5954
6353
  }
@@ -5964,27 +6363,31 @@ function runLoop(config) {
5964
6363
  loopCompletedRef,
5965
6364
  config,
5966
6365
  iteration,
5967
- session.id
6366
+ session.id,
6367
+ worktreePath
5968
6368
  )
5969
6369
  )
5970
6370
  );
5971
6371
  const completionStream = createCompletionStream(
5972
6372
  sessionStore,
6373
+ git,
5973
6374
  session,
5974
6375
  config,
5975
6376
  startTime,
5976
- loopCompletedRef
6377
+ loopCompletedRef,
6378
+ worktreePath
5977
6379
  );
5978
6380
  return pipe3(
5979
6381
  Stream9.succeed(loopStarted),
6382
+ Stream9.concat(Stream9.succeed(worktreeCreated)),
5980
6383
  Stream9.concat(discoveryStream),
5981
6384
  Stream9.concat(iterationsStream),
5982
6385
  Stream9.concat(completionStream)
5983
6386
  );
5984
6387
  }).pipe(
5985
6388
  // Also catch setup errors (e.g., session creation failure)
5986
- Effect20.catchAll(
5987
- (error) => Effect20.succeed(
6389
+ Effect22.catchAll(
6390
+ (error) => Effect22.succeed(
5988
6391
  Stream9.succeed({
5989
6392
  _tag: "LoopFailed",
5990
6393
  error: {
@@ -5997,12 +6400,38 @@ function runLoop(config) {
5997
6400
  )
5998
6401
  );
5999
6402
  }
6000
- function createCompletionStream(sessionStore, session, config, startTime, loopCompletedRef) {
6001
- return Stream9.fromEffect(
6002
- Effect20.gen(function* () {
6403
+ function createCompletionStream(sessionStore, git, session, config, startTime, loopCompletedRef, worktreePath) {
6404
+ return Stream9.unwrap(
6405
+ Effect22.gen(function* () {
6003
6406
  const endTimeUtc = yield* DateTime10.now;
6004
6407
  const durationMs = DateTime10.toEpochMillis(endTimeUtc) - startTime;
6005
- const completed = yield* Ref11.get(loopCompletedRef);
6408
+ const completed = yield* Ref12.get(loopCompletedRef);
6409
+ yield* git.commitChanges(session.id, `feat: complete session ${session.id}`).pipe(
6410
+ Effect22.tapError(
6411
+ (error) => Effect22.logDebug("Final commit failed, continuing cleanup", {
6412
+ sessionId: session.id,
6413
+ error: String(error)
6414
+ })
6415
+ ),
6416
+ Effect22.orElseSucceed(() => void 0)
6417
+ );
6418
+ yield* git.removeWorktree(session.id).pipe(
6419
+ Effect22.tapError(
6420
+ (error) => Effect22.logDebug("Worktree cleanup failed, continuing", {
6421
+ sessionId: session.id,
6422
+ worktreePath,
6423
+ error: String(error)
6424
+ })
6425
+ ),
6426
+ Effect22.orElseSucceed(() => void 0)
6427
+ );
6428
+ const cleanupTimeUtc = yield* DateTime10.now;
6429
+ const cleanupTime = DateTime10.toEpochMillis(cleanupTimeUtc);
6430
+ const worktreeRemoved = {
6431
+ _tag: "WorktreeRemoved",
6432
+ sessionId: session.id,
6433
+ timestamp: cleanupTime
6434
+ };
6006
6435
  const summary = {
6007
6436
  iterations: config.maxIterations,
6008
6437
  success: completed,
@@ -6014,16 +6443,16 @@ function createCompletionStream(sessionStore, session, config, startTime, loopCo
6014
6443
  ...session,
6015
6444
  status: completed ? "completed" : "paused"
6016
6445
  }).pipe(
6017
- Effect20.tapError(
6018
- (error) => Effect20.logDebug("Session update failed, continuing", {
6446
+ Effect22.tapError(
6447
+ (error) => Effect22.logDebug("Session update failed, continuing", {
6019
6448
  sessionId: session.id,
6020
6449
  error: String(error)
6021
6450
  })
6022
6451
  ),
6023
- Effect20.orElseSucceed(() => void 0)
6452
+ Effect22.orElseSucceed(() => void 0)
6024
6453
  );
6025
- const event = { _tag: "LoopCompleted", summary };
6026
- return event;
6454
+ const loopCompleted = { _tag: "LoopCompleted", summary };
6455
+ return Stream9.fromIterable([worktreeRemoved, loopCompleted]);
6027
6456
  })
6028
6457
  );
6029
6458
  }
@@ -6032,7 +6461,7 @@ function createCompletionStream(sessionStore, session, config, startTime, loopCo
6032
6461
  function run(options) {
6033
6462
  const { config, consumer: consumerType = "headless", onEvent } = options;
6034
6463
  const events = runLoop(config);
6035
- const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect21.sync(() => onEvent(event)))) : events;
6464
+ const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect23.sync(() => onEvent(event)))) : events;
6036
6465
  const eventsWithLayers = eventsWithCallback.pipe(
6037
6466
  Stream10.provideLayer(ProductionLayers)
6038
6467
  );
@@ -6045,7 +6474,7 @@ function run(options) {
6045
6474
  function runTest(options, mockEvents) {
6046
6475
  const { config, onEvent } = options;
6047
6476
  const events = runLoop(config);
6048
- const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect21.sync(() => onEvent(event)))) : events;
6477
+ const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect23.sync(() => onEvent(event)))) : events;
6049
6478
  const layers = mockEvents ? createTestLayers(mockEvents) : TestLayers;
6050
6479
  const eventsWithLayers = eventsWithCallback.pipe(Stream10.provideLayer(layers));
6051
6480
  return eventsWithLayers.pipe(Stream10.runDrain);
@@ -6053,11 +6482,11 @@ function runTest(options, mockEvents) {
6053
6482
  function collectEvents(config, mockEvents) {
6054
6483
  const events = runLoop(config);
6055
6484
  const layers = mockEvents ? createTestLayers(mockEvents) : TestLayers;
6056
- return events.pipe(Stream10.provideLayer(layers), Stream10.runCollect).pipe(Effect21.map((chunk) => Array.from(chunk)));
6485
+ return events.pipe(Stream10.provideLayer(layers), Stream10.runCollect).pipe(Effect23.map((chunk) => Array.from(chunk)));
6057
6486
  }
6058
6487
  function main(config) {
6059
6488
  const consumerType = process.stdout.isTTY ? "tui" : "headless";
6060
- return run({ config, consumer: consumerType }).pipe(Effect21.runPromise);
6489
+ return run({ config, consumer: consumerType }).pipe(Effect23.runPromise);
6061
6490
  }
6062
6491
 
6063
6492
  // src/services/index.ts
@@ -6065,7 +6494,7 @@ init_esm_shims();
6065
6494
 
6066
6495
  // src/index.ts
6067
6496
  var program = new Command();
6068
- program.name("ferix-code").description("Composable RALPH loops for AI coding agents").version(package_default.version).argument("<task>", "Task description or path to PRD file").option("-i, --iterations <n>", "Maximum iterations", "1").option("-v, --verify <commands...>", "Verification commands").option("--branch <name>", "Git branch to create").option("--push", "Push branch after completion").option("--pr", "Create PR after pushing").action(async (task, options) => {
6497
+ program.name("ferix-code").description("Composable RALPH loops for AI coding agents").version(package_default.version, "-v, --version", "Output the version number").argument("<task>", "Task description or path to PRD file").option("-i, --iterations <n>", "Maximum iterations", "1").option("-c, --verify <commands...>", "Verification commands to run").option("--branch <name>", "Git branch to create").option("--push", "Push branch after completion").option("--pr", "Create PR after pushing").action(async (task, options) => {
6069
6498
  const config = {
6070
6499
  task,
6071
6500
  maxIterations: Number.parseInt(options.iterations, 10),
@@ -6110,6 +6539,7 @@ export {
6110
6539
  ExecutionModeSchema,
6111
6540
  FerixParser,
6112
6541
  FileLoggerConfigSchema,
6542
+ FileSystemGit,
6113
6543
  FileSystemGuardrails,
6114
6544
  FileSystemPlan,
6115
6545
  FileSystemProgress,
@@ -6117,6 +6547,8 @@ export {
6117
6547
  GeneratedTaskListSchema,
6118
6548
  GeneratedTaskSchema,
6119
6549
  GeneratedTaskStatusSchema,
6550
+ Git,
6551
+ GitError,
6120
6552
  GuardrailAddedEventSchema,
6121
6553
  GuardrailSchema,
6122
6554
  GuardrailSeveritySchema,
@@ -6146,6 +6578,7 @@ export {
6146
6578
  LoopStartedEventSchema,
6147
6579
  LoopStatusSchema,
6148
6580
  LoopSummarySchema,
6581
+ MemoryGit,
6149
6582
  MemoryGuardrails,
6150
6583
  MemoryPlan,
6151
6584
  MemoryProgress,
@@ -6218,6 +6651,8 @@ export {
6218
6651
  ToolStartEventSchema,
6219
6652
  ToolUseEventSchema,
6220
6653
  ViewModeSchema,
6654
+ WorktreeCreatedEventSchema,
6655
+ WorktreeRemovedEventSchema,
6221
6656
  buildPrompt,
6222
6657
  collectEvents,
6223
6658
  createHeadlessConsumer,