ferix-code 0.0.2 → 0.0.3

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 (2) hide show
  1. package/dist/index.js +1036 -1186
  2. package/package.json +6 -1
package/dist/index.js CHANGED
@@ -20,11 +20,11 @@ var __copyProps = (to, from, except, desc) => {
20
20
  };
21
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
22
 
23
- // ../../node_modules/.bun/tsup@8.5.1+f2002c7b4d902bba/node_modules/tsup/assets/esm_shims.js
23
+ // ../../node_modules/.bun/tsup@8.5.1+7ba260eccd18f7a2/node_modules/tsup/assets/esm_shims.js
24
24
  import path from "path";
25
25
  import { fileURLToPath } from "url";
26
26
  var init_esm_shims = __esm({
27
- "../../node_modules/.bun/tsup@8.5.1+f2002c7b4d902bba/node_modules/tsup/assets/esm_shims.js"() {
27
+ "../../node_modules/.bun/tsup@8.5.1+7ba260eccd18f7a2/node_modules/tsup/assets/esm_shims.js"() {
28
28
  "use strict";
29
29
  }
30
30
  });
@@ -32,7 +32,6 @@ var init_esm_shims = __esm({
32
32
  // src/commands/code/consumers/tui/tags/registry.ts
33
33
  var registry_exports = {};
34
34
  __export(registry_exports, {
35
- createTagRendererRegistry: () => createTagRendererRegistry,
36
35
  tagRendererRegistry: () => tagRendererRegistry
37
36
  });
38
37
  function createTagRendererRegistry() {
@@ -71,7 +70,7 @@ import { Command } from "commander";
71
70
  // package.json
72
71
  var package_default = {
73
72
  name: "ferix-code",
74
- version: "0.0.2",
73
+ version: "0.0.3",
75
74
  description: "Composable RALPH loops for AI coding agents - v2 with Effect",
76
75
  type: "module",
77
76
  bin: {
@@ -87,6 +86,10 @@ var package_default = {
87
86
  "check-types": "tsc --noEmit",
88
87
  test: "bun test",
89
88
  "test:watch": "bun test --watch",
89
+ "test:unit": "bun test tests/unit",
90
+ "test:integration": "bun test tests/integration",
91
+ "test:errors": "bun test tests/error-paths",
92
+ "test:properties": "bun test tests/properties",
90
93
  bump: "npm version prerelease --preid=beta --workspaces=false && bun run build && bun publish --tag beta",
91
94
  patch: "npm version patch --workspaces=false && bun run build && bun publish --tag latest"
92
95
  },
@@ -103,6 +106,7 @@ var package_default = {
103
106
  "@ferix/server": "*",
104
107
  "@types/bun": "latest",
105
108
  "@types/node": "^22.15.3",
109
+ "fast-check": "^3.22.0",
106
110
  tsup: "^8.4.0",
107
111
  typescript: "5.9.2"
108
112
  },
@@ -126,7 +130,8 @@ init_esm_shims();
126
130
 
127
131
  // src/commands/code/action.ts
128
132
  init_esm_shims();
129
- import { Effect as Effect24, Stream as Stream10 } from "effect";
133
+ import { Effect as Effect20, Layer as Layer12, Stream as Stream9 } from "effect";
134
+ import { humanId as humanId2 } from "human-id";
130
135
 
131
136
  // src/commands/code/consumers/index.ts
132
137
  init_esm_shims();
@@ -953,7 +958,6 @@ tagRendererRegistry.register({
953
958
  });
954
959
 
955
960
  // src/commands/code/consumers/tui/tags/index.ts
956
- init_registry();
957
961
  function styleFerixTags(line, width) {
958
962
  const { tagRendererRegistry: registry } = (init_registry(), __toCommonJS(registry_exports));
959
963
  return registry.style(line, width);
@@ -1169,15 +1173,6 @@ function validateToolInput(tool, input) {
1169
1173
  }
1170
1174
  return S.decodeUnknownEither(schema)(input);
1171
1175
  }
1172
- var isReadToolInput = S.is(ReadToolInputSchema);
1173
- var isEditToolInput = S.is(EditToolInputSchema);
1174
- var isWriteToolInput = S.is(WriteToolInputSchema);
1175
- var isBashToolInput = S.is(BashToolInputSchema);
1176
- var isGlobToolInput = S.is(GlobToolInputSchema);
1177
- var isGrepToolInput = S.is(GrepToolInputSchema);
1178
- var isTaskToolInput = S.is(TaskToolInputSchema);
1179
- var isWebFetchToolInput = S.is(WebFetchToolInputSchema);
1180
- var isWebSearchToolInput = S.is(WebSearchToolInputSchema);
1181
1176
 
1182
1177
  // src/commands/code/consumers/tui/tools/registry.ts
1183
1178
  var brightWhite = (s) => pc13.bold(pc13.white(s));
@@ -1480,7 +1475,9 @@ var loopStartedReducer = {
1480
1475
  task: event.config.task,
1481
1476
  maxIterations: event.config.maxIterations,
1482
1477
  status: "running",
1483
- startTime: event.timestamp
1478
+ startTime: event.timestamp,
1479
+ yolo: event.config.yolo ?? false,
1480
+ debug: event.config.debug ?? false
1484
1481
  })
1485
1482
  };
1486
1483
  var loopCompletedReducer = {
@@ -1663,7 +1660,9 @@ function createInitialState() {
1663
1660
  selectedTaskIndex: 0,
1664
1661
  scrollOffset: 0,
1665
1662
  userScrolled: false,
1666
- gitPushed: false
1663
+ gitPushed: false,
1664
+ yolo: false,
1665
+ debug: false
1667
1666
  };
1668
1667
  }
1669
1668
  function scroll(state, direction, lines, maxOffset) {
@@ -1795,6 +1794,12 @@ function renderStatusBar(state, width) {
1795
1794
  parts.push(
1796
1795
  `${colors.brand(symbols.diamond)} ${colors.brightWhite("FERIX")} ${colors.brand(symbols.diamond)}`
1797
1796
  );
1797
+ if (state.yolo) {
1798
+ parts.push(colors.warning("\u26A0 YOLO"));
1799
+ }
1800
+ if (state.debug) {
1801
+ parts.push(colors.brightMagenta("DEBUG"));
1802
+ }
1798
1803
  if (state.status === "running") {
1799
1804
  const spinner = getSpinner();
1800
1805
  const mode = getModeDisplay(state.executionMode, state.currentTaskId);
@@ -2445,9 +2450,6 @@ var ANSIOutput = class {
2445
2450
  }
2446
2451
  };
2447
2452
 
2448
- // src/commands/code/consumers/tui/output/buffer.ts
2449
- init_esm_shims();
2450
-
2451
2453
  // src/commands/code/consumers/tui/consumer.ts
2452
2454
  var activeOutput = null;
2453
2455
  function setupSignalHandlers() {
@@ -2601,7 +2603,7 @@ ${errorText}
2601
2603
 
2602
2604
  // src/commands/code/layers/index.ts
2603
2605
  init_esm_shims();
2604
- import { Layer as Layer14 } from "effect";
2606
+ import { Layer as Layer11 } from "effect";
2605
2607
 
2606
2608
  // src/commands/code/layers/git/file-system.ts
2607
2609
  init_esm_shims();
@@ -2645,7 +2647,9 @@ var RetryExhaustedError = class extends Data.TaggedError(
2645
2647
  "RetryExhaustedError"
2646
2648
  ) {
2647
2649
  };
2648
- var MetricsError = class extends Data.TaggedError("MetricsError") {
2650
+ var StateStoreError = class extends Data.TaggedError("StateStoreError") {
2651
+ };
2652
+ var PromptStoreError = class extends Data.TaggedError("PromptStoreError") {
2649
2653
  };
2650
2654
 
2651
2655
  // src/commands/code/services/git.ts
@@ -3008,140 +3012,11 @@ var FileSystemGit = {
3008
3012
  Live
3009
3013
  };
3010
3014
 
3011
- // src/commands/code/layers/git/memory.ts
3012
- init_esm_shims();
3013
- import { Effect as Effect5, Layer as Layer2, Ref as Ref3 } from "effect";
3014
- var BRANCH_PREFIX2 = "ferix";
3015
- function getBranchName2(sessionId) {
3016
- return `${BRANCH_PREFIX2}/${sessionId}`;
3017
- }
3018
- function createMemoryGitService(stateRef, commitCounterRef) {
3019
- return {
3020
- createWorktree: (sessionId, _baseBranch) => Effect5.gen(function* () {
3021
- const state = yield* Ref3.get(stateRef);
3022
- const existing = state.get(sessionId);
3023
- if (existing) {
3024
- return existing.path;
3025
- }
3026
- const path2 = `.ferix/worktrees/${sessionId}`;
3027
- const branch = getBranchName2(sessionId);
3028
- const worktree = {
3029
- path: path2,
3030
- branch,
3031
- commits: []
3032
- };
3033
- state.set(sessionId, worktree);
3034
- yield* Ref3.set(stateRef, state);
3035
- return path2;
3036
- }),
3037
- removeWorktree: (sessionId) => Effect5.gen(function* () {
3038
- const state = yield* Ref3.get(stateRef);
3039
- state.delete(sessionId);
3040
- yield* Ref3.set(stateRef, state);
3041
- }),
3042
- removeWorktreeKeepBranch: (sessionId) => Effect5.gen(function* () {
3043
- const state = yield* Ref3.get(stateRef);
3044
- state.delete(sessionId);
3045
- yield* Ref3.set(stateRef, state);
3046
- }),
3047
- getWorktreePath: (sessionId) => Effect5.gen(function* () {
3048
- const state = yield* Ref3.get(stateRef);
3049
- const worktree = state.get(sessionId);
3050
- return worktree?.path;
3051
- }),
3052
- commitChanges: (sessionId, message) => Effect5.gen(function* () {
3053
- const state = yield* Ref3.get(stateRef);
3054
- const worktree = state.get(sessionId);
3055
- if (!worktree) {
3056
- return yield* Effect5.fail(
3057
- new GitError({
3058
- message: `Worktree not found for session: ${sessionId}`,
3059
- operation: "commit"
3060
- })
3061
- );
3062
- }
3063
- const counter = yield* Ref3.updateAndGet(commitCounterRef, (n) => n + 1);
3064
- const hash = `test-commit-${counter}`;
3065
- const updatedWorktree = {
3066
- ...worktree,
3067
- commits: [...worktree.commits, `${hash}: ${message}`]
3068
- };
3069
- state.set(sessionId, updatedWorktree);
3070
- yield* Ref3.set(stateRef, state);
3071
- return hash;
3072
- }),
3073
- pushBranch: (sessionId) => Effect5.gen(function* () {
3074
- const state = yield* Ref3.get(stateRef);
3075
- const worktree = state.get(sessionId);
3076
- if (!worktree) {
3077
- return yield* Effect5.fail(
3078
- new GitError({
3079
- message: `Worktree not found for session: ${sessionId}`,
3080
- operation: "push"
3081
- })
3082
- );
3083
- }
3084
- }),
3085
- createPR: (sessionId, title, _body, _baseBranch) => Effect5.gen(function* () {
3086
- const state = yield* Ref3.get(stateRef);
3087
- const worktree = state.get(sessionId);
3088
- if (!worktree) {
3089
- return yield* Effect5.fail(
3090
- new GitError({
3091
- message: `Worktree not found for session: ${sessionId}`,
3092
- operation: "createPR"
3093
- })
3094
- );
3095
- }
3096
- const slug = title.toLowerCase().replace(/\s+/g, "-").slice(0, 30);
3097
- return `https://github.com/test/repo/pull/${slug}`;
3098
- }),
3099
- getCurrentBranch: () => Effect5.succeed("main"),
3100
- // Default to main for tests
3101
- renameBranch: (sessionId, displayName) => Effect5.gen(function* () {
3102
- const state = yield* Ref3.get(stateRef);
3103
- const worktree = state.get(sessionId);
3104
- if (!worktree) {
3105
- return yield* Effect5.fail(
3106
- new GitError({
3107
- message: `Worktree not found for session: ${sessionId}`,
3108
- operation: "renameBranch"
3109
- })
3110
- );
3111
- }
3112
- const newBranchName = `${BRANCH_PREFIX2}/${displayName}`;
3113
- const updatedWorktree = {
3114
- ...worktree,
3115
- branch: newBranchName
3116
- };
3117
- state.set(sessionId, updatedWorktree);
3118
- yield* Ref3.set(stateRef, state);
3119
- return newBranchName;
3120
- }),
3121
- getBranchName: getBranchName2
3122
- };
3123
- }
3124
- function layer() {
3125
- return Layer2.effect(
3126
- Git,
3127
- Effect5.gen(function* () {
3128
- const stateRef = yield* Ref3.make(/* @__PURE__ */ new Map());
3129
- const commitCounterRef = yield* Ref3.make(0);
3130
- return createMemoryGitService(stateRef, commitCounterRef);
3131
- })
3132
- );
3133
- }
3134
- var Live2 = layer();
3135
- var MemoryGit = {
3136
- Live: Live2,
3137
- layer
3138
- };
3139
-
3140
3015
  // src/commands/code/layers/guardrails/file-system.ts
3141
3016
  init_esm_shims();
3142
3017
  import { mkdir as mkdir2, readFile as readFile2, writeFile } from "fs/promises";
3143
3018
  import { join as join2 } from "path";
3144
- import { DateTime, Effect as Effect6, Layer as Layer3 } from "effect";
3019
+ import { DateTime, Effect as Effect5, Layer as Layer2 } from "effect";
3145
3020
 
3146
3021
  // src/commands/code/domain/index.ts
3147
3022
  init_esm_shims();
@@ -3210,13 +3085,6 @@ var StreamEventEnvelopeSchema = S2.Struct({
3210
3085
  type: S2.Literal("stream_event"),
3211
3086
  event: S2.Unknown
3212
3087
  });
3213
- var ClaudeCliEventSchema = S2.Union(
3214
- ContentBlockStartSchema,
3215
- ContentBlockDeltaSchema,
3216
- ContentBlockStopSchema,
3217
- AssistantMessageSchema,
3218
- StreamEventEnvelopeSchema
3219
- );
3220
3088
  var isContentBlockStart = S2.is(ContentBlockStartSchema);
3221
3089
  var isContentBlockDelta = S2.is(ContentBlockDeltaSchema);
3222
3090
  var isContentBlockStop = S2.is(ContentBlockStopSchema);
@@ -3226,8 +3094,6 @@ var isTextDelta = S2.is(TextDeltaSchema);
3226
3094
  var isInputJsonDelta = S2.is(InputJsonDeltaSchema);
3227
3095
  var isToolUseContentBlock = S2.is(ToolUseContentBlockSchema);
3228
3096
  var isTextContentBlock = S2.is(TextContentBlockSchema);
3229
- var decodeClaudeCliEvent = S2.decodeUnknown(ClaudeCliEventSchema);
3230
- var decodeClaudeCliEventSync = S2.decodeUnknownSync(ClaudeCliEventSchema);
3231
3097
 
3232
3098
  // src/commands/code/domain/schemas/cli-output-opencode.ts
3233
3099
  init_esm_shims();
@@ -3250,15 +3116,6 @@ var OpenCodeToolUseEventSchema = S3.Struct({
3250
3116
  type: S3.Literal("tool_use"),
3251
3117
  part: OpenCodeToolPartSchema
3252
3118
  });
3253
- var OpenCodeStepPartSchema = S3.Struct({}).pipe(
3254
- S3.extend(S3.Record({ key: S3.String, value: S3.Unknown }))
3255
- );
3256
- var OpenCodeStepStartSchema = S3.Struct({
3257
- type: S3.Literal("step_start"),
3258
- timestamp: S3.Number,
3259
- sessionID: S3.String,
3260
- part: S3.optional(OpenCodeStepPartSchema)
3261
- });
3262
3119
  var OpenCodeTokensSchema = S3.Struct({}).pipe(
3263
3120
  S3.extend(S3.Record({ key: S3.String, value: S3.Unknown }))
3264
3121
  );
@@ -3270,20 +3127,9 @@ var OpenCodeStepFinishSchema = S3.Struct({
3270
3127
  tokens: S3.optional(OpenCodeTokensSchema),
3271
3128
  cost: S3.optional(OpenCodeCostSchema)
3272
3129
  });
3273
- var OpenCodeCliEventSchema = S3.Union(
3274
- OpenCodeTextEventSchema,
3275
- OpenCodeToolUseEventSchema,
3276
- OpenCodeStepStartSchema,
3277
- OpenCodeStepFinishSchema
3278
- );
3279
3130
  var isOpenCodeTextEvent = S3.is(OpenCodeTextEventSchema);
3280
3131
  var isOpenCodeToolUseEvent = S3.is(OpenCodeToolUseEventSchema);
3281
- var isOpenCodeStepStart = S3.is(OpenCodeStepStartSchema);
3282
3132
  var isOpenCodeStepFinish = S3.is(OpenCodeStepFinishSchema);
3283
- var decodeOpenCodeCliEvent = S3.decodeUnknown(OpenCodeCliEventSchema);
3284
- var decodeOpenCodeCliEventSync = S3.decodeUnknownSync(
3285
- OpenCodeCliEventSchema
3286
- );
3287
3133
 
3288
3134
  // src/commands/code/domain/schemas/config.ts
3289
3135
  init_esm_shims();
@@ -3314,7 +3160,11 @@ var LoopConfigSchema = S4.Struct({
3314
3160
  verbose: S4.optional(S4.Boolean),
3315
3161
  prompts: S4.optional(PromptConfigSchema),
3316
3162
  /** LLM provider to use. Defaults to "claude". */
3317
- provider: S4.optional(ProviderNameSchema)
3163
+ provider: S4.optional(ProviderNameSchema),
3164
+ /** Skip all permission prompts (YOLO mode). Use with caution. */
3165
+ yolo: S4.optional(S4.Boolean),
3166
+ /** Enable debug logging to .ferix/logs/<session>.log */
3167
+ debug: S4.optional(S4.Boolean)
3318
3168
  });
3319
3169
  var LoopSummarySchema = S4.Struct({
3320
3170
  iterations: S4.Number,
@@ -3330,7 +3180,6 @@ var LoopErrorSchema = S4.Struct({
3330
3180
  phase: S4.String,
3331
3181
  iteration: S4.optional(S4.Number)
3332
3182
  });
3333
- var decodeLoopConfig = S4.decodeUnknown(LoopConfigSchema);
3334
3183
 
3335
3184
  // src/commands/code/domain/schemas/events.ts
3336
3185
  init_esm_shims();
@@ -3348,12 +3197,7 @@ var TaskStatusSchema = S5.Literal(
3348
3197
  "failed",
3349
3198
  "skipped"
3350
3199
  );
3351
- var PhaseStatusSchema = S5.Literal(
3352
- "pending",
3353
- "in_progress",
3354
- "done",
3355
- "failed"
3356
- );
3200
+ var PhaseStatusSchema = S5.Literal("pending", "in_progress", "done", "failed");
3357
3201
  var CriterionStatusSchema = S5.Literal("pending", "passed", "failed");
3358
3202
  var PhaseSchema = S5.Struct({
3359
3203
  id: S5.String,
@@ -3392,7 +3236,6 @@ var PlanSchema = S5.Struct({
3392
3236
  context: S5.optional(S5.String),
3393
3237
  tasks: S5.Array(TaskSchema)
3394
3238
  });
3395
- var decodePlan = S5.decodeUnknown(PlanSchema);
3396
3239
  var decodePlanData = S5.decodeUnknown(PlanDataSchema);
3397
3240
 
3398
3241
  // src/commands/code/domain/schemas/shared.ts
@@ -3591,51 +3434,12 @@ var PRCreatedEventSchema = taggedEvent("PRCreated", {
3591
3434
  title: S7.String,
3592
3435
  timestamp: S7.Number
3593
3436
  });
3594
- var SessionNameGeneratedEventSchema = taggedEvent(
3595
- "SessionNameGenerated",
3596
- {
3597
- sessionId: S7.String,
3598
- /** Task-based descriptive name (kebab-case slug, e.g., "add-dark-mode-toggle") */
3599
- displayName: S7.String,
3600
- timestamp: S7.Number
3601
- }
3602
- );
3603
- var DomainEventSchema = S7.Union(
3604
- LoopStartedEventSchema,
3605
- LoopCompletedEventSchema,
3606
- LoopFailedEventSchema,
3607
- DiscoveryStartedEventSchema,
3608
- DiscoveryCompletedEventSchema,
3609
- IterationStartedEventSchema,
3610
- IterationCompletedEventSchema,
3611
- LLMTextEventSchema,
3612
- LLMToolStartEventSchema,
3613
- LLMToolUseEventSchema,
3614
- LLMToolEndEventSchema,
3615
- TasksDefinedEventSchema,
3616
- PhasesDefinedEventSchema,
3617
- CriteriaDefinedEventSchema,
3618
- PhaseStartedEventSchema,
3619
- PhaseCompletedEventSchema,
3620
- PhaseFailedEventSchema,
3621
- CriterionPassedEventSchema,
3622
- CriterionFailedEventSchema,
3623
- CheckPassedEventSchema,
3624
- CheckFailedEventSchema,
3625
- ReviewCompleteEventSchema,
3626
- TaskCompletedEventSchema,
3627
- PlanCreatedEventSchema,
3628
- PlanUpdatedEventSchema,
3629
- PlanUpdateFailedEventSchema,
3630
- LearningRecordedEventSchema,
3631
- GuardrailAddedEventSchema,
3632
- ProgressUpdatedEventSchema,
3633
- WorktreeCreatedEventSchema,
3634
- WorktreeRemovedEventSchema,
3635
- BranchPushedEventSchema,
3636
- PRCreatedEventSchema,
3637
- SessionNameGeneratedEventSchema
3638
- );
3437
+ var SessionNameGeneratedEventSchema = taggedEvent("SessionNameGenerated", {
3438
+ sessionId: S7.String,
3439
+ /** Task-based descriptive name (kebab-case slug, e.g., "add-dark-mode-toggle") */
3440
+ displayName: S7.String,
3441
+ timestamp: S7.Number
3442
+ });
3639
3443
 
3640
3444
  // src/commands/code/domain/schemas/guardrails.ts
3641
3445
  init_esm_shims();
@@ -3655,12 +3459,11 @@ var GuardrailsFileSchema = S8.Struct({
3655
3459
  createdAt: S8.String,
3656
3460
  guardrails: S8.Array(GuardrailSchema)
3657
3461
  });
3658
- var decodeGuardrail = S8.decodeUnknown(GuardrailSchema);
3659
3462
  var decodeGuardrailsFile = S8.decodeUnknown(GuardrailsFileSchema);
3660
3463
 
3661
3464
  // src/commands/code/domain/schemas/llm.ts
3662
3465
  init_esm_shims();
3663
- import { Either as Either3, Schema as S9 } from "effect";
3466
+ import { Schema as S9 } from "effect";
3664
3467
  var TextEventSchema = S9.TaggedStruct("Text", {
3665
3468
  text: S9.String
3666
3469
  });
@@ -3671,10 +3474,6 @@ var ToolUseEventSchema = S9.TaggedStruct("ToolUse", {
3671
3474
  tool: S9.String,
3672
3475
  input: S9.Unknown
3673
3476
  });
3674
- var ValidatedToolUseEventSchema = S9.TaggedStruct("ToolUse", {
3675
- tool: S9.String,
3676
- input: AnyToolInputSchema
3677
- });
3678
3477
  var ToolEndEventSchema = S9.TaggedStruct("ToolEnd", {
3679
3478
  tool: S9.String
3680
3479
  });
@@ -3688,95 +3487,108 @@ var LLMEventSchema = S9.Union(
3688
3487
  ToolEndEventSchema,
3689
3488
  DoneEventSchema
3690
3489
  );
3691
- var decodeLLMEvent = S9.decodeUnknown(LLMEventSchema);
3692
3490
 
3693
3491
  // src/commands/code/domain/schemas/logger.ts
3694
3492
  init_esm_shims();
3695
- import { Schema as S10 } from "effect";
3696
- var LogLevelSchema = S10.Literal("debug", "info", "warn", "error");
3697
- var LogEntrySchema = S10.Struct({
3698
- level: LogLevelSchema,
3699
- message: S10.String,
3700
- timestamp: S10.String,
3701
- context: S10.optional(S10.Record({ key: S10.String, value: S10.Unknown }))
3702
- });
3703
- var ConsoleLoggerConfigSchema = S10.Struct({
3704
- level: S10.optional(LogLevelSchema),
3705
- colors: S10.optional(S10.Boolean)
3706
- });
3707
- var FileLoggerConfigSchema = S10.Struct({
3708
- path: S10.optional(S10.String),
3709
- level: S10.optional(LogLevelSchema)
3710
- });
3711
3493
 
3712
3494
  // src/commands/code/domain/schemas/program.ts
3713
3495
  init_esm_shims();
3714
- import { Schema as S11 } from "effect";
3715
- var ConsumerTypeSchema = S11.Literal("tui", "headless", "none");
3716
- var RunOptionsDataSchema = S11.Struct({
3717
- config: LoopConfigSchema,
3718
- consumer: S11.optional(ConsumerTypeSchema)
3719
- });
3496
+ import { Schema as S10 } from "effect";
3497
+ var ConsumerTypeSchema = S10.Literal("tui", "headless", "none");
3720
3498
 
3721
3499
  // src/commands/code/domain/schemas/progress.ts
3722
3500
  init_esm_shims();
3723
- import { Schema as S12 } from "effect";
3724
- var ProgressActionSchema = S12.Literal(
3501
+ import { Schema as S11 } from "effect";
3502
+ var ProgressActionSchema = S11.Literal(
3725
3503
  "started",
3726
3504
  "completed",
3727
3505
  "failed",
3728
3506
  "learning"
3729
3507
  );
3730
- var ProgressEntrySchema = S12.Struct({
3731
- iteration: S12.Number,
3732
- timestamp: S12.String,
3733
- taskId: S12.String,
3508
+ var ProgressEntrySchema = S11.Struct({
3509
+ iteration: S11.Number,
3510
+ timestamp: S11.String,
3511
+ taskId: S11.String,
3734
3512
  action: ProgressActionSchema,
3735
- summary: S12.String,
3736
- learnings: S12.optional(S12.Array(S12.String)),
3737
- filesModified: S12.optional(S12.Array(S12.String))
3513
+ summary: S11.String,
3514
+ learnings: S11.optional(S11.Array(S11.String)),
3515
+ filesModified: S11.optional(S11.Array(S11.String))
3738
3516
  });
3739
- var ProgressFileSchema = S12.Struct({
3740
- sessionId: S12.String,
3741
- createdAt: S12.String,
3742
- entries: S12.Array(ProgressEntrySchema)
3517
+ var ProgressFileSchema = S11.Struct({
3518
+ sessionId: S11.String,
3519
+ createdAt: S11.String,
3520
+ entries: S11.Array(ProgressEntrySchema)
3743
3521
  });
3744
- var decodeProgressEntry = S12.decodeUnknown(ProgressEntrySchema);
3745
- var decodeProgressFile = S12.decodeUnknown(ProgressFileSchema);
3522
+ var decodeProgressFile = S11.decodeUnknown(ProgressFileSchema);
3523
+ function formatProgressMd(progress, originalTask) {
3524
+ const lines = [];
3525
+ lines.push("# Session Progress Log");
3526
+ lines.push("");
3527
+ lines.push(`## Session: ${progress.sessionId}`);
3528
+ lines.push(`Started: ${progress.createdAt}`);
3529
+ if (originalTask) {
3530
+ lines.push(`Task: ${originalTask}`);
3531
+ }
3532
+ lines.push("");
3533
+ lines.push("---");
3534
+ lines.push("");
3535
+ for (const entry of progress.entries) {
3536
+ lines.push(`### Iteration ${entry.iteration} - ${entry.timestamp}`);
3537
+ lines.push(`**Task**: ${entry.taskId}`);
3538
+ lines.push(`**Status**: ${capitalizeFirst(entry.action)}`);
3539
+ lines.push(`**Summary**: ${entry.summary}`);
3540
+ if (entry.filesModified && entry.filesModified.length > 0) {
3541
+ lines.push(`**Files Modified**: ${entry.filesModified.join(", ")}`);
3542
+ }
3543
+ if (entry.learnings && entry.learnings.length > 0) {
3544
+ lines.push("**Learnings**:");
3545
+ for (const learning of entry.learnings) {
3546
+ lines.push(`- ${learning}`);
3547
+ }
3548
+ }
3549
+ lines.push("");
3550
+ lines.push("---");
3551
+ lines.push("");
3552
+ }
3553
+ return lines.join("\n");
3554
+ }
3555
+ function capitalizeFirst(str) {
3556
+ return str.charAt(0).toUpperCase() + str.slice(1);
3557
+ }
3746
3558
 
3747
3559
  // src/commands/code/domain/schemas/session.ts
3748
3560
  init_esm_shims();
3749
- import { Schema as S13 } from "effect";
3750
- var SessionStatusSchema = S13.Literal(
3561
+ import { Schema as S12 } from "effect";
3562
+ var SessionStatusSchema = S12.Literal(
3751
3563
  "active",
3752
3564
  "completed",
3753
3565
  "failed",
3754
3566
  "paused"
3755
3567
  );
3756
- var SessionSchema = S13.Struct({
3757
- id: S13.String,
3758
- createdAt: S13.String,
3568
+ var SessionSchema = S12.Struct({
3569
+ id: S12.String,
3570
+ createdAt: S12.String,
3759
3571
  status: SessionStatusSchema,
3760
- originalTask: S13.String,
3761
- completedTasks: S13.Array(S13.String),
3762
- currentTaskId: S13.optional(S13.String),
3763
- worktreePath: S13.optional(S13.String),
3764
- branchName: S13.optional(S13.String),
3572
+ originalTask: S12.String,
3573
+ completedTasks: S12.Array(S12.String),
3574
+ currentTaskId: S12.optional(S12.String),
3575
+ worktreePath: S12.optional(S12.String),
3576
+ branchName: S12.optional(S12.String),
3765
3577
  /** Task-based descriptive name (kebab-case slug, e.g., "add-dark-mode-toggle") */
3766
- displayName: S13.optional(S13.String),
3578
+ displayName: S12.optional(S12.String),
3767
3579
  /** The branch ferix was started from - used as PR base branch */
3768
- baseBranch: S13.optional(S13.String)
3580
+ baseBranch: S12.optional(S12.String)
3769
3581
  });
3770
- var decodeSession = S13.decodeUnknown(SessionSchema);
3582
+ var decodeSession = S12.decodeUnknown(SessionSchema);
3771
3583
 
3772
3584
  // src/commands/code/domain/schemas/signal-factories.ts
3773
3585
  init_esm_shims();
3774
- import { Schema as S15 } from "effect";
3586
+ import { Schema as S14 } from "effect";
3775
3587
 
3776
3588
  // src/commands/code/domain/schemas/signals.ts
3777
3589
  init_esm_shims();
3778
- import { Schema as S14 } from "effect";
3779
- var taggedFromData2 = (tag, dataSchema) => S14.TaggedStruct(tag, dataSchema.fields);
3590
+ import { Schema as S13 } from "effect";
3591
+ var taggedFromData2 = (tag, dataSchema) => S13.TaggedStruct(tag, dataSchema.fields);
3780
3592
  var TasksDefinedSignalSchema = taggedFromData2(
3781
3593
  "TasksDefined",
3782
3594
  TasksDefinedDataSchema
@@ -3809,8 +3621,8 @@ var CriterionFailedSignalSchema = taggedFromData2(
3809
3621
  "CriterionFailed",
3810
3622
  CriterionFailedDataSchema
3811
3623
  );
3812
- var CheckPassedSignalSchema = S14.TaggedStruct("CheckPassed", {});
3813
- var CheckFailedSignalSchema = S14.TaggedStruct("CheckFailed", {});
3624
+ var CheckPassedSignalSchema = S13.TaggedStruct("CheckPassed", {});
3625
+ var CheckFailedSignalSchema = S13.TaggedStruct("CheckFailed", {});
3814
3626
  var ReviewCompleteSignalSchema = taggedFromData2(
3815
3627
  "ReviewComplete",
3816
3628
  ReviewCompleteDataSchema
@@ -3819,30 +3631,26 @@ var TaskCompleteSignalSchema = taggedFromData2(
3819
3631
  "TaskComplete",
3820
3632
  TaskCompleteSignalDataSchema
3821
3633
  );
3822
- var LoopCompleteSignalSchema = S14.TaggedStruct("LoopComplete", {});
3823
- var SessionNameDefinedSignalSchema = S14.TaggedStruct(
3634
+ var LoopCompleteSignalSchema = S13.TaggedStruct("LoopComplete", {});
3635
+ var SessionNameDefinedSignalSchema = S13.TaggedStruct(
3824
3636
  "SessionNameDefined",
3825
3637
  {
3826
3638
  /** Kebab-case slug, e.g., "add-dark-mode-toggle" */
3827
- name: S14.String
3639
+ name: S13.String
3828
3640
  }
3829
3641
  );
3830
- var LearningCategorySchema = S14.Literal(
3831
- "success",
3832
- "failure",
3833
- "optimization"
3834
- );
3835
- var LearningSignalSchema = S14.TaggedStruct("Learning", {
3836
- content: S14.String,
3837
- category: S14.optional(LearningCategorySchema)
3838
- });
3839
- var GuardrailSignalSchema = S14.TaggedStruct("Guardrail", {
3840
- pattern: S14.String,
3841
- sign: S14.String,
3842
- avoidance: S14.String,
3843
- severity: S14.Literal("warning", "critical")
3844
- });
3845
- var SignalSchema = S14.Union(
3642
+ var LearningCategorySchema = S13.Literal("success", "failure", "optimization");
3643
+ var LearningSignalSchema = S13.TaggedStruct("Learning", {
3644
+ content: S13.String,
3645
+ category: S13.optional(LearningCategorySchema)
3646
+ });
3647
+ var GuardrailSignalSchema = S13.TaggedStruct("Guardrail", {
3648
+ pattern: S13.String,
3649
+ sign: S13.String,
3650
+ avoidance: S13.String,
3651
+ severity: S13.Literal("warning", "critical")
3652
+ });
3653
+ var SignalSchema = S13.Union(
3846
3654
  TasksDefinedSignalSchema,
3847
3655
  PhasesDefinedSignalSchema,
3848
3656
  CriteriaDefinedSignalSchema,
@@ -3860,81 +3668,79 @@ var SignalSchema = S14.Union(
3860
3668
  GuardrailSignalSchema,
3861
3669
  SessionNameDefinedSignalSchema
3862
3670
  );
3863
- var decodeSignal = S14.decodeUnknown(SignalSchema);
3864
- var decodeSignalSync = S14.decodeUnknownSync(SignalSchema);
3865
3671
 
3866
3672
  // src/commands/code/domain/schemas/signal-factories.ts
3867
3673
  function createTasksDefinedSignal(input) {
3868
- return S15.decodeUnknownEither(TasksDefinedSignalSchema)({
3674
+ return S14.decodeUnknownEither(TasksDefinedSignalSchema)({
3869
3675
  _tag: "TasksDefined",
3870
3676
  tasks: input.tasks
3871
3677
  });
3872
3678
  }
3873
3679
  function createPhasesDefinedSignal(input) {
3874
- return S15.decodeUnknownEither(PhasesDefinedSignalSchema)({
3680
+ return S14.decodeUnknownEither(PhasesDefinedSignalSchema)({
3875
3681
  _tag: "PhasesDefined",
3876
3682
  taskId: input.taskId,
3877
3683
  phases: input.phases
3878
3684
  });
3879
3685
  }
3880
3686
  function createCriteriaDefinedSignal(input) {
3881
- return S15.decodeUnknownEither(CriteriaDefinedSignalSchema)({
3687
+ return S14.decodeUnknownEither(CriteriaDefinedSignalSchema)({
3882
3688
  _tag: "CriteriaDefined",
3883
3689
  taskId: input.taskId,
3884
3690
  criteria: input.criteria
3885
3691
  });
3886
3692
  }
3887
3693
  function createPhaseStartedSignal(input) {
3888
- return S15.decodeUnknownEither(PhaseStartedSignalSchema)({
3694
+ return S14.decodeUnknownEither(PhaseStartedSignalSchema)({
3889
3695
  _tag: "PhaseStarted",
3890
3696
  phaseId: input.phaseId
3891
3697
  });
3892
3698
  }
3893
3699
  function createPhaseCompletedSignal(input) {
3894
- return S15.decodeUnknownEither(PhaseCompletedSignalSchema)({
3700
+ return S14.decodeUnknownEither(PhaseCompletedSignalSchema)({
3895
3701
  _tag: "PhaseCompleted",
3896
3702
  phaseId: input.phaseId
3897
3703
  });
3898
3704
  }
3899
3705
  function createPhaseFailedSignal(input) {
3900
- return S15.decodeUnknownEither(PhaseFailedSignalSchema)({
3706
+ return S14.decodeUnknownEither(PhaseFailedSignalSchema)({
3901
3707
  _tag: "PhaseFailed",
3902
3708
  phaseId: input.phaseId,
3903
3709
  reason: input.reason
3904
3710
  });
3905
3711
  }
3906
3712
  function createCriterionPassedSignal(input) {
3907
- return S15.decodeUnknownEither(CriterionPassedSignalSchema)({
3713
+ return S14.decodeUnknownEither(CriterionPassedSignalSchema)({
3908
3714
  _tag: "CriterionPassed",
3909
3715
  criterionId: input.criterionId
3910
3716
  });
3911
3717
  }
3912
3718
  function createCriterionFailedSignal(input) {
3913
- return S15.decodeUnknownEither(CriterionFailedSignalSchema)({
3719
+ return S14.decodeUnknownEither(CriterionFailedSignalSchema)({
3914
3720
  _tag: "CriterionFailed",
3915
3721
  criterionId: input.criterionId,
3916
3722
  reason: input.reason
3917
3723
  });
3918
3724
  }
3919
3725
  function createCheckPassedSignal(_input) {
3920
- return S15.decodeUnknownEither(CheckPassedSignalSchema)({
3726
+ return S14.decodeUnknownEither(CheckPassedSignalSchema)({
3921
3727
  _tag: "CheckPassed"
3922
3728
  });
3923
3729
  }
3924
3730
  function createCheckFailedSignal(_input) {
3925
- return S15.decodeUnknownEither(CheckFailedSignalSchema)({
3731
+ return S14.decodeUnknownEither(CheckFailedSignalSchema)({
3926
3732
  _tag: "CheckFailed"
3927
3733
  });
3928
3734
  }
3929
3735
  function createLearningSignal(input) {
3930
- return S15.decodeUnknownEither(LearningSignalSchema)({
3736
+ return S14.decodeUnknownEither(LearningSignalSchema)({
3931
3737
  _tag: "Learning",
3932
3738
  content: input.content,
3933
3739
  category: input.category
3934
3740
  });
3935
3741
  }
3936
3742
  function createGuardrailSignal(input) {
3937
- return S15.decodeUnknownEither(GuardrailSignalSchema)({
3743
+ return S14.decodeUnknownEither(GuardrailSignalSchema)({
3938
3744
  _tag: "Guardrail",
3939
3745
  pattern: input.pattern,
3940
3746
  sign: input.sign,
@@ -3943,12 +3749,49 @@ function createGuardrailSignal(input) {
3943
3749
  });
3944
3750
  }
3945
3751
  function createSessionNameDefinedSignal(input) {
3946
- return S15.decodeUnknownEither(SessionNameDefinedSignalSchema)({
3752
+ return S14.decodeUnknownEither(SessionNameDefinedSignalSchema)({
3947
3753
  _tag: "SessionNameDefined",
3948
3754
  name: input.name
3949
3755
  });
3950
3756
  }
3951
3757
 
3758
+ // src/commands/code/domain/schemas/state.ts
3759
+ init_esm_shims();
3760
+ import { Schema as S15 } from "effect";
3761
+ var TaskSummarySchema = S15.Struct({
3762
+ total: S15.Number,
3763
+ done: S15.Number,
3764
+ inProgress: S15.Number,
3765
+ pending: S15.Number
3766
+ });
3767
+ var PhaseStateSchema = S15.Struct({
3768
+ id: S15.String,
3769
+ description: S15.String,
3770
+ status: S15.Literal("pending", "in_progress", "done", "failed")
3771
+ });
3772
+ var CriterionStateSchema = S15.Struct({
3773
+ id: S15.String,
3774
+ description: S15.String,
3775
+ status: S15.Literal("pending", "passed", "failed")
3776
+ });
3777
+ var CurrentTaskSchema = S15.Struct({
3778
+ id: S15.String,
3779
+ title: S15.String,
3780
+ description: S15.String,
3781
+ phases: S15.Array(PhaseStateSchema),
3782
+ criteria: S15.Array(CriterionStateSchema)
3783
+ });
3784
+ var SessionStateSchema = S15.Struct({
3785
+ sessionId: S15.String,
3786
+ originalTask: S15.String,
3787
+ iteration: S15.Number,
3788
+ maxIterations: S15.Number,
3789
+ taskSummary: TaskSummarySchema,
3790
+ currentTask: S15.NullOr(CurrentTaskSchema),
3791
+ recentProgress: S15.Array(S15.String)
3792
+ });
3793
+ var decodeSessionState = S15.decodeUnknown(SessionStateSchema);
3794
+
3952
3795
  // src/commands/code/domain/schemas/task-generation.ts
3953
3796
  init_esm_shims();
3954
3797
  import { Schema as S16 } from "effect";
@@ -3961,49 +3804,24 @@ var GeneratedTaskStatusSchema = S16.Literal(
3961
3804
  var GeneratedTaskSchema = S16.Struct({
3962
3805
  id: S16.String,
3963
3806
  title: S16.String,
3964
- status: GeneratedTaskStatusSchema
3807
+ description: S16.String,
3808
+ status: GeneratedTaskStatusSchema,
3809
+ steps: S16.Array(S16.String)
3965
3810
  });
3966
- var GeneratedTaskListSchema = S16.Array(GeneratedTaskSchema);
3967
- var STATUS_ICONS = {
3968
- done: "[x]",
3969
- in_progress: "[~]",
3970
- pending: "[ ]",
3971
- failed: "[!]"
3972
- };
3973
- function formatTasksMd(tasks) {
3974
- const completedCount = tasks.filter((t) => t.status === "done").length;
3975
- const totalCount = tasks.length;
3976
- const lines = [
3977
- "# Tasks",
3978
- "",
3979
- `## Status: ${completedCount}/${totalCount} complete`,
3980
- ""
3981
- ];
3982
- const currentTaskId = tasks.find(
3983
- (t) => t.status === "in_progress" || t.status === "pending"
3984
- )?.id;
3985
- for (const task of tasks) {
3986
- const icon = STATUS_ICONS[task.status];
3987
- const currentMarker = task.id === currentTaskId ? " \u2190 current" : "";
3988
- lines.push(`- ${icon} **Task ${task.id}**: ${task.title}${currentMarker}`);
3989
- }
3990
- lines.push("");
3991
- lines.push("---");
3992
- lines.push("");
3993
- lines.push(`*Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}*`);
3994
- return lines.join("\n");
3811
+ var TasksFileSchema = S16.Struct({
3812
+ sessionId: S16.String,
3813
+ originalTask: S16.String,
3814
+ tasks: S16.Array(GeneratedTaskSchema)
3815
+ });
3816
+ function formatTasksJson(tasksFile) {
3817
+ return JSON.stringify(tasksFile, null, 2);
3995
3818
  }
3996
3819
 
3997
3820
  // src/commands/code/domain/schemas/tui.ts
3998
3821
  init_esm_shims();
3999
3822
  import { Schema as S17 } from "effect";
4000
3823
  var ViewModeSchema = S17.Literal("logs", "tasks", "detail");
4001
- var LoopStatusSchema = S17.Literal(
4002
- "idle",
4003
- "running",
4004
- "complete",
4005
- "error"
4006
- );
3824
+ var LoopStatusSchema = S17.Literal("idle", "running", "complete", "error");
4007
3825
  var ExecutionModeSchema = S17.Literal(
4008
3826
  "idle",
4009
3827
  "discovery",
@@ -4020,11 +3838,7 @@ var TUIPhaseStatusSchema = S17.Literal(
4020
3838
  "done",
4021
3839
  "failed"
4022
3840
  );
4023
- var TUICriterionStatusSchema = S17.Literal(
4024
- "pending",
4025
- "passed",
4026
- "failed"
4027
- );
3841
+ var TUICriterionStatusSchema = S17.Literal("pending", "passed", "failed");
4028
3842
  var TUITaskStatusSchema = S17.Literal(
4029
3843
  "pending",
4030
3844
  "in_progress",
@@ -4080,7 +3894,11 @@ var TUIStateSchema = S17.Struct({
4080
3894
  // Git
4081
3895
  gitBranch: S17.optional(S17.String),
4082
3896
  gitPushed: S17.Boolean,
4083
- prUrl: S17.optional(S17.String)
3897
+ prUrl: S17.optional(S17.String),
3898
+ // YOLO mode (skip permission prompts)
3899
+ yolo: S17.Boolean,
3900
+ // Debug mode (logging enabled)
3901
+ debug: S17.Boolean
4084
3902
  });
4085
3903
 
4086
3904
  // src/commands/code/services/guardrails-store.ts
@@ -4092,14 +3910,14 @@ var GuardrailsStore = class extends Context2.Tag("@ferix/GuardrailsStore")() {
4092
3910
  // src/commands/code/layers/guardrails/file-system.ts
4093
3911
  var PLANS_DIR = ".ferix/plans";
4094
3912
  function ensureDir(dirPath) {
4095
- return Effect6.tryPromise({
3913
+ return Effect5.tryPromise({
4096
3914
  try: () => mkdir2(dirPath, { recursive: true }),
4097
3915
  catch: (error) => new GuardrailsStoreError({
4098
3916
  message: `Failed to create directory: ${dirPath}`,
4099
3917
  operation: "add",
4100
3918
  cause: error
4101
3919
  })
4102
- }).pipe(Effect6.asVoid);
3920
+ }).pipe(Effect5.asVoid);
4103
3921
  }
4104
3922
  function getSessionDir(sessionId) {
4105
3923
  return join2(process.cwd(), PLANS_DIR, sessionId);
@@ -4111,8 +3929,8 @@ function serializeGuardrails(guardrails) {
4111
3929
  return JSON.stringify(guardrails, null, 2);
4112
3930
  }
4113
3931
  function deserializeGuardrails(json) {
4114
- return Effect6.gen(function* () {
4115
- const parsed = yield* Effect6.try({
3932
+ return Effect5.gen(function* () {
3933
+ const parsed = yield* Effect5.try({
4116
3934
  try: () => JSON.parse(json),
4117
3935
  catch: (error) => new GuardrailsStoreError({
4118
3936
  message: `Invalid JSON in guardrails file: ${String(error)}`,
@@ -4121,7 +3939,7 @@ function deserializeGuardrails(json) {
4121
3939
  })
4122
3940
  });
4123
3941
  const validated = yield* decodeGuardrailsFile(parsed).pipe(
4124
- Effect6.mapError(
3942
+ Effect5.mapError(
4125
3943
  (error) => new GuardrailsStoreError({
4126
3944
  message: `Guardrails validation failed: ${String(error)}`,
4127
3945
  operation: "load",
@@ -4140,11 +3958,11 @@ function createEmptyGuardrails(sessionId, createdAt) {
4140
3958
  };
4141
3959
  }
4142
3960
  var make2 = {
4143
- add: (sessionId, guardrail) => Effect6.gen(function* () {
3961
+ add: (sessionId, guardrail) => Effect5.gen(function* () {
4144
3962
  const sessionDir = getSessionDir(sessionId);
4145
3963
  yield* ensureDir(sessionDir);
4146
3964
  const guardrailsPath = getGuardrailsPath(sessionId);
4147
- const existing = yield* Effect6.tryPromise({
3965
+ const existing = yield* Effect5.tryPromise({
4148
3966
  try: async () => {
4149
3967
  try {
4150
3968
  const content = await readFile2(guardrailsPath, "utf-8");
@@ -4162,7 +3980,7 @@ var make2 = {
4162
3980
  let guardrails;
4163
3981
  if (existing) {
4164
3982
  guardrails = yield* deserializeGuardrails(existing).pipe(
4165
- Effect6.mapError(
3983
+ Effect5.mapError(
4166
3984
  (err) => new GuardrailsStoreError({
4167
3985
  message: err.message,
4168
3986
  operation: "add",
@@ -4178,7 +3996,7 @@ var make2 = {
4178
3996
  ...guardrails,
4179
3997
  guardrails: [...guardrails.guardrails, guardrail]
4180
3998
  };
4181
- yield* Effect6.tryPromise({
3999
+ yield* Effect5.tryPromise({
4182
4000
  try: () => writeFile(
4183
4001
  guardrailsPath,
4184
4002
  serializeGuardrails(updatedGuardrails),
@@ -4191,9 +4009,9 @@ var make2 = {
4191
4009
  })
4192
4010
  });
4193
4011
  }),
4194
- load: (sessionId) => Effect6.gen(function* () {
4012
+ load: (sessionId) => Effect5.gen(function* () {
4195
4013
  const guardrailsPath = getGuardrailsPath(sessionId);
4196
- const content = yield* Effect6.tryPromise({
4014
+ const content = yield* Effect5.tryPromise({
4197
4015
  try: async () => {
4198
4016
  try {
4199
4017
  return await readFile2(guardrailsPath, "utf-8");
@@ -4213,146 +4031,39 @@ var make2 = {
4213
4031
  }
4214
4032
  return yield* deserializeGuardrails(content);
4215
4033
  }),
4216
- getActive: (sessionId) => Effect6.gen(function* () {
4034
+ getActive: (sessionId) => Effect5.gen(function* () {
4217
4035
  const guardrails = yield* make2.load(sessionId);
4218
4036
  return guardrails.guardrails;
4219
4037
  })
4220
4038
  };
4221
- var Live3 = Layer3.succeed(GuardrailsStore, make2);
4039
+ var Live2 = Layer2.succeed(GuardrailsStore, make2);
4222
4040
  var FileSystemGuardrails = {
4223
- Live: Live3
4224
- };
4225
-
4226
- // src/commands/code/layers/guardrails/memory.ts
4227
- init_esm_shims();
4228
- import { DateTime as DateTime2, Effect as Effect7, Layer as Layer4, Ref as Ref4 } from "effect";
4229
- function createMemoryGuardrailsStore(stateRef) {
4230
- return {
4231
- add: (sessionId, guardrail) => Effect7.gen(function* () {
4232
- const state = yield* Ref4.get(stateRef);
4233
- let guardrails = state.get(sessionId);
4234
- if (!guardrails) {
4235
- const now = yield* DateTime2.now;
4236
- guardrails = {
4237
- sessionId,
4238
- createdAt: DateTime2.formatIso(now),
4239
- guardrails: []
4240
- };
4241
- }
4242
- const updatedGuardrails = {
4243
- ...guardrails,
4244
- guardrails: [...guardrails.guardrails, guardrail]
4245
- };
4246
- state.set(sessionId, updatedGuardrails);
4247
- yield* Ref4.set(stateRef, state);
4248
- }),
4249
- load: (sessionId) => Effect7.gen(function* () {
4250
- const state = yield* Ref4.get(stateRef);
4251
- const guardrails = state.get(sessionId);
4252
- if (!guardrails) {
4253
- const now = yield* DateTime2.now;
4254
- return {
4255
- sessionId,
4256
- createdAt: DateTime2.formatIso(now),
4257
- guardrails: []
4258
- };
4259
- }
4260
- return guardrails;
4261
- }),
4262
- getActive: (sessionId) => Effect7.gen(function* () {
4263
- const state = yield* Ref4.get(stateRef);
4264
- const guardrails = state.get(sessionId);
4265
- if (!guardrails) {
4266
- return [];
4267
- }
4268
- return guardrails.guardrails;
4269
- })
4270
- };
4271
- }
4272
- function layer2() {
4273
- return Layer4.effect(
4274
- GuardrailsStore,
4275
- Effect7.gen(function* () {
4276
- const stateRef = yield* Ref4.make(/* @__PURE__ */ new Map());
4277
- return createMemoryGuardrailsStore(stateRef);
4278
- })
4279
- );
4280
- }
4281
- var Live4 = layer2();
4282
- var MemoryGuardrails = {
4283
- Live: Live4,
4284
- layer: layer2
4285
- };
4286
-
4287
- // src/commands/code/layers/llm/mock.ts
4288
- init_esm_shims();
4289
- import { Effect as Effect8, Layer as Layer5, Schema as S18, Stream as Stream4 } from "effect";
4290
-
4291
- // src/commands/code/services/llm.ts
4292
- init_esm_shims();
4293
- import { Context as Context3 } from "effect";
4294
- var LLM = class extends Context3.Tag("@ferix/LLM")() {
4295
- };
4296
-
4297
- // src/commands/code/layers/llm/mock.ts
4298
- var MockLLMConfigSchema = S18.Struct({
4299
- events: S18.Array(LLMEventSchema),
4300
- delayMs: S18.optional(S18.Number)
4301
- });
4302
- function createMockLLM(config) {
4303
- return {
4304
- execute: (_prompt, _options) => {
4305
- const baseStream = Stream4.fromIterable(config.events);
4306
- if (config.delayMs !== void 0 && config.delayMs > 0) {
4307
- const delay = config.delayMs;
4308
- return baseStream.pipe(Stream4.tap(() => Effect8.sleep(delay)));
4309
- }
4310
- return baseStream;
4311
- }
4312
- };
4313
- }
4314
- var defaultMockEvents = [
4315
- { _tag: "Text", text: "Processing task...\n" },
4316
- { _tag: "ToolStart", tool: "Read" },
4317
- { _tag: "ToolEnd", tool: "Read" },
4318
- { _tag: "Text", text: "Task completed successfully.\n" },
4319
- {
4320
- _tag: "Done",
4321
- output: "Processing task...\nTask completed successfully.\n"
4322
- }
4323
- ];
4324
- var defaultMock = createMockLLM({ events: defaultMockEvents });
4325
- var Live5 = Layer5.succeed(LLM, defaultMock);
4326
- function layer3(config) {
4327
- return Layer5.succeed(LLM, createMockLLM(config));
4328
- }
4329
- var Mock = {
4330
- Live: Live5,
4331
- layer: layer3,
4332
- createMockLLM
4041
+ Live: Live2
4333
4042
  };
4334
4043
 
4335
4044
  // src/commands/code/layers/llm/providers/index.ts
4336
4045
  init_esm_shims();
4337
- import { Effect as Effect11 } from "effect";
4046
+ import { Effect as Effect8 } from "effect";
4338
4047
 
4339
4048
  // src/commands/code/layers/llm/types.ts
4340
4049
  init_esm_shims();
4341
- import { Schema as S19 } from "effect";
4342
- var PermissionModeSchema = S19.Literal("acceptEdits", "yolo", "prompt");
4343
- var ProviderConfigSchema = S19.Struct({
4050
+ import { Schema as S18 } from "effect";
4051
+ var PermissionModeSchema = S18.Literal("acceptEdits", "yolo", "prompt");
4052
+ var ProviderConfigSchema = S18.Struct({
4344
4053
  /** Provider name */
4345
4054
  name: ProviderNameSchema,
4346
4055
  /** CLI command to execute */
4347
- cliCommand: S19.String,
4056
+ cliCommand: S18.String,
4348
4057
  /** Default arguments for the CLI */
4349
- args: S19.Array(S19.String),
4058
+ args: S18.Array(S18.String),
4350
4059
  /** Environment variables to pass */
4351
- env: S19.optional(S19.Record({ key: S19.String, value: S19.String })),
4060
+ env: S18.optional(S18.Record({ key: S18.String, value: S18.String })),
4352
4061
  /** Permission mode for the CLI */
4353
- permissions: S19.optional(PermissionModeSchema),
4062
+ permissions: S18.optional(PermissionModeSchema),
4354
4063
  /** URL for installation instructions */
4355
- installUrl: S19.String
4064
+ installUrl: S18.String,
4065
+ /** Arguments to pass when YOLO mode is enabled */
4066
+ yoloArgs: S18.optional(S18.Array(S18.String))
4356
4067
  });
4357
4068
  var RAW_PROVIDER_CONFIGS = {
4358
4069
  claude: {
@@ -4367,28 +4078,31 @@ var RAW_PROVIDER_CONFIGS = {
4367
4078
  "--include-partial-messages"
4368
4079
  ],
4369
4080
  permissions: "acceptEdits",
4370
- installUrl: "https://docs.anthropic.com/claude-code"
4081
+ installUrl: "https://docs.anthropic.com/claude-code",
4082
+ yoloArgs: ["--dangerously-skip-permissions"]
4371
4083
  },
4372
4084
  cursor: {
4373
4085
  name: "cursor",
4374
4086
  cliCommand: "cursor-agent",
4375
4087
  args: ["--print", "--force", "--output-format", "stream-json"],
4376
4088
  permissions: "acceptEdits",
4377
- installUrl: "https://cursor.sh/agent"
4089
+ installUrl: "https://cursor.sh/agent",
4090
+ yoloArgs: ["--yolo"]
4378
4091
  },
4379
4092
  opencode: {
4380
4093
  name: "opencode",
4381
4094
  cliCommand: "opencode",
4382
4095
  args: ["run", "--format", "json"],
4383
- installUrl: "https://opencode.ai/docs/"
4096
+ installUrl: "https://opencode.ai/docs/",
4097
+ yoloArgs: ["--yolo"]
4384
4098
  }
4385
4099
  };
4386
- var ProviderConfigsSchema = S19.Record({
4100
+ var ProviderConfigsSchema = S18.Record({
4387
4101
  key: ProviderNameSchema,
4388
4102
  value: ProviderConfigSchema
4389
4103
  });
4390
4104
  var validateProviderConfigs = () => {
4391
- const decoded = S19.decodeUnknownSync(ProviderConfigsSchema)(
4105
+ const decoded = S18.decodeUnknownSync(ProviderConfigsSchema)(
4392
4106
  RAW_PROVIDER_CONFIGS
4393
4107
  );
4394
4108
  return decoded;
@@ -4401,16 +4115,28 @@ init_esm_shims();
4401
4115
  // src/commands/code/layers/llm/provider-factory.ts
4402
4116
  init_esm_shims();
4403
4117
  import { spawn } from "child_process";
4404
- import { Effect as Effect9, Layer as Layer6, Stream as Stream5 } from "effect";
4118
+ import { Effect as Effect6, Layer as Layer3, Stream as Stream4 } from "effect";
4119
+
4120
+ // src/commands/code/services/llm.ts
4121
+ init_esm_shims();
4122
+ import { Context as Context3 } from "effect";
4123
+ var LLM = class extends Context3.Tag("@ferix/LLM")() {
4124
+ };
4125
+
4126
+ // src/commands/code/layers/llm/provider-factory.ts
4405
4127
  function createProvider(name, createStream, checkAvailable) {
4406
4128
  const config = PROVIDER_CONFIGS[name];
4407
4129
  return {
4408
4130
  name,
4409
4131
  execute: (prompt, options) => {
4410
- return Stream5.unwrap(
4132
+ return Stream4.unwrap(
4411
4133
  checkAvailable(name).pipe(
4412
- Effect9.map(() => {
4413
- const args = name === "opencode" ? [...config.args, prompt] : [...config.args, "-p", prompt];
4134
+ Effect6.map(() => {
4135
+ let args = [...config.args];
4136
+ if (options?.yolo && config.yoloArgs) {
4137
+ args.push(...config.yoloArgs);
4138
+ }
4139
+ args = name === "opencode" ? [...args, prompt] : [...args, "-p", prompt];
4414
4140
  const child = spawn(config.cliCommand, args, {
4415
4141
  stdio: ["inherit", "pipe", "pipe"],
4416
4142
  cwd: options?.cwd,
@@ -4428,7 +4154,7 @@ function createProvider(name, createStream, checkAvailable) {
4428
4154
  };
4429
4155
  }
4430
4156
  function createProviderLayer(provider) {
4431
- return Layer6.succeed(LLM, provider);
4157
+ return Layer3.succeed(LLM, provider);
4432
4158
  }
4433
4159
 
4434
4160
  // src/commands/code/layers/llm/stream.ts
@@ -4439,13 +4165,13 @@ init_esm_shims();
4439
4165
 
4440
4166
  // src/commands/code/layers/llm/providers/parsers/stream-json.ts
4441
4167
  init_esm_shims();
4442
- import { Either as Either4 } from "effect";
4168
+ import { Either as Either3 } from "effect";
4443
4169
  function parseJsonLine(line) {
4444
4170
  if (!line.startsWith("{")) {
4445
4171
  return null;
4446
4172
  }
4447
- return Either4.getOrNull(
4448
- Either4.try({ try: () => JSON.parse(line), catch: () => null })
4173
+ return Either3.getOrNull(
4174
+ Either3.try({ try: () => JSON.parse(line), catch: () => null })
4449
4175
  );
4450
4176
  }
4451
4177
  function extractText(json) {
@@ -4484,8 +4210,8 @@ function extractToolInfo(json) {
4484
4210
  return null;
4485
4211
  }
4486
4212
  function safeParseJson(jsonStr) {
4487
- return Either4.getOrNull(
4488
- Either4.try({ try: () => JSON.parse(jsonStr), catch: () => null })
4213
+ return Either3.getOrNull(
4214
+ Either3.try({ try: () => JSON.parse(jsonStr), catch: () => null })
4489
4215
  );
4490
4216
  }
4491
4217
  function unwrapStreamEvent(json) {
@@ -4498,7 +4224,7 @@ function unwrapStreamEvent(json) {
4498
4224
  // src/commands/code/layers/llm/stream-factory.ts
4499
4225
  init_esm_shims();
4500
4226
  import { createInterface } from "readline";
4501
- import { Effect as Effect10, Stream as Stream6 } from "effect";
4227
+ import { Effect as Effect7, Stream as Stream5 } from "effect";
4502
4228
  function handleToolEvent(toolInfo, toolState, emit) {
4503
4229
  if (toolInfo.type === "start") {
4504
4230
  toolState.currentTool = toolInfo.name;
@@ -4522,7 +4248,7 @@ function handleToolEvent(toolInfo, toolState, emit) {
4522
4248
  }
4523
4249
  }
4524
4250
  function createLLMEventStream(child, parser, providerName) {
4525
- return Stream6.async((emit) => {
4251
+ return Stream5.async((emit) => {
4526
4252
  const outputChunks = [];
4527
4253
  const toolState = { currentTool: "", inputChunks: [] };
4528
4254
  const stdout = child.stdout;
@@ -4530,7 +4256,7 @@ function createLLMEventStream(child, parser, providerName) {
4530
4256
  emit.fail(
4531
4257
  new LLMError({ message: "Failed to get stdout from child process" })
4532
4258
  );
4533
- return Effect10.void;
4259
+ return Effect7.void;
4534
4260
  }
4535
4261
  const rl = createInterface({
4536
4262
  input: stdout,
@@ -4569,7 +4295,7 @@ function createLLMEventStream(child, parser, providerName) {
4569
4295
  })
4570
4296
  );
4571
4297
  });
4572
- return Effect10.sync(() => {
4298
+ return Effect7.sync(() => {
4573
4299
  child.kill("SIGTERM");
4574
4300
  });
4575
4301
  });
@@ -4603,9 +4329,9 @@ var ClaudeProvider = createProvider(
4603
4329
  (child) => createEventStream(child, "Claude"),
4604
4330
  checkProviderAvailable
4605
4331
  );
4606
- var Live6 = createProviderLayer(ClaudeProvider);
4332
+ var Live3 = createProviderLayer(ClaudeProvider);
4607
4333
  var ClaudeCLI = {
4608
- Live: Live6,
4334
+ Live: Live3,
4609
4335
  Provider: ClaudeProvider
4610
4336
  };
4611
4337
 
@@ -4616,9 +4342,9 @@ var CursorProvider = createProvider(
4616
4342
  (child) => createEventStream(child, "Cursor"),
4617
4343
  checkProviderAvailable
4618
4344
  );
4619
- var Live7 = createProviderLayer(CursorProvider);
4345
+ var Live4 = createProviderLayer(CursorProvider);
4620
4346
  var CursorCLI = {
4621
- Live: Live7,
4347
+ Live: Live4,
4622
4348
  Provider: CursorProvider
4623
4349
  };
4624
4350
 
@@ -4630,13 +4356,13 @@ init_esm_shims();
4630
4356
 
4631
4357
  // src/commands/code/layers/llm/providers/parsers/opencode.ts
4632
4358
  init_esm_shims();
4633
- import { Either as Either5 } from "effect";
4359
+ import { Either as Either4 } from "effect";
4634
4360
  function parseJsonLine2(line) {
4635
4361
  if (!line.startsWith("{")) {
4636
4362
  return null;
4637
4363
  }
4638
- return Either5.getOrNull(
4639
- Either5.try({ try: () => JSON.parse(line), catch: () => null })
4364
+ return Either4.getOrNull(
4365
+ Either4.try({ try: () => JSON.parse(line), catch: () => null })
4640
4366
  );
4641
4367
  }
4642
4368
  function isStepFinish(json) {
@@ -4697,16 +4423,16 @@ var OpenCodeProvider = createProvider(
4697
4423
  (child) => createOpenCodeEventStream(child, "OpenCode"),
4698
4424
  checkProviderAvailable
4699
4425
  );
4700
- var Live8 = createProviderLayer(OpenCodeProvider);
4426
+ var Live5 = createProviderLayer(OpenCodeProvider);
4701
4427
  var OpenCodeCLI = {
4702
- Live: Live8,
4428
+ Live: Live5,
4703
4429
  Provider: OpenCodeProvider
4704
4430
  };
4705
4431
 
4706
4432
  // src/commands/code/layers/llm/providers/index.ts
4707
4433
  var OpenCodeCLI2 = OpenCodeCLI;
4708
4434
  function isCommandAvailable(command) {
4709
- return Effect11.tryPromise({
4435
+ return Effect8.tryPromise({
4710
4436
  try: async () => {
4711
4437
  const { execSync } = await import("child_process");
4712
4438
  try {
@@ -4717,13 +4443,13 @@ function isCommandAvailable(command) {
4717
4443
  }
4718
4444
  },
4719
4445
  catch: () => false
4720
- }).pipe(Effect11.orElseSucceed(() => false));
4446
+ }).pipe(Effect8.orElseSucceed(() => false));
4721
4447
  }
4722
4448
  function checkProviderAvailable(name) {
4723
4449
  const config = PROVIDER_CONFIGS[name];
4724
4450
  return isCommandAvailable(config.cliCommand).pipe(
4725
- Effect11.flatMap(
4726
- (available) => available ? Effect11.void : Effect11.fail(
4451
+ Effect8.flatMap(
4452
+ (available) => available ? Effect8.void : Effect8.fail(
4727
4453
  new LLMError({
4728
4454
  message: `Provider "${name}" is not available. The CLI command "${config.cliCommand}" was not found.
4729
4455
 
@@ -4753,7 +4479,7 @@ function createProviderLayer2(name) {
4753
4479
  init_esm_shims();
4754
4480
  import { access as access2, mkdir as mkdir3, readdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
4755
4481
  import { join as join3 } from "path";
4756
- import { Effect as Effect12, Layer as Layer7 } from "effect";
4482
+ import { Effect as Effect9, Layer as Layer4 } from "effect";
4757
4483
 
4758
4484
  // src/commands/code/services/plan-store.ts
4759
4485
  init_esm_shims();
@@ -4764,14 +4490,14 @@ var PlanStore = class extends Context4.Tag("@ferix/PlanStore")() {
4764
4490
  // src/commands/code/layers/plan/file-system.ts
4765
4491
  var PLANS_DIR2 = ".ferix/plans";
4766
4492
  function ensureDir2(dirPath) {
4767
- return Effect12.tryPromise({
4493
+ return Effect9.tryPromise({
4768
4494
  try: () => mkdir3(dirPath, { recursive: true }),
4769
4495
  catch: (error) => new PlanStoreError({
4770
4496
  message: `Failed to create directory: ${dirPath}`,
4771
4497
  operation: "create",
4772
4498
  cause: error
4773
4499
  })
4774
- }).pipe(Effect12.asVoid);
4500
+ }).pipe(Effect9.asVoid);
4775
4501
  }
4776
4502
  function getSessionDir2(sessionId) {
4777
4503
  return join3(process.cwd(), PLANS_DIR2, sessionId);
@@ -4786,8 +4512,8 @@ function serializePlan(plan) {
4786
4512
  return JSON.stringify(plan, null, 2);
4787
4513
  }
4788
4514
  function deserializePlan(json, planId) {
4789
- return Effect12.gen(function* () {
4790
- const parsed = yield* Effect12.try({
4515
+ return Effect9.gen(function* () {
4516
+ const parsed = yield* Effect9.try({
4791
4517
  try: () => JSON.parse(json),
4792
4518
  catch: (error) => new PlanStoreError({
4793
4519
  message: `Invalid JSON in plan file: ${String(error)}`,
@@ -4796,7 +4522,7 @@ function deserializePlan(json, planId) {
4796
4522
  })
4797
4523
  });
4798
4524
  const validated = yield* decodePlanData(parsed).pipe(
4799
- Effect12.mapError(
4525
+ Effect9.mapError(
4800
4526
  (error) => new PlanStoreError({
4801
4527
  message: `Plan validation failed: ${String(error)}`,
4802
4528
  operation: "load",
@@ -4811,10 +4537,10 @@ function deserializePlan(json, planId) {
4811
4537
  });
4812
4538
  }
4813
4539
  var make3 = {
4814
- create: (sessionId, plan) => Effect12.gen(function* () {
4540
+ create: (sessionId, plan) => Effect9.gen(function* () {
4815
4541
  const sessionDir = getSessionDir2(sessionId);
4816
4542
  yield* ensureDir2(sessionDir);
4817
- const existingPlans = yield* Effect12.tryPromise({
4543
+ const existingPlans = yield* Effect9.tryPromise({
4818
4544
  try: async () => {
4819
4545
  try {
4820
4546
  const files = await readdir(sessionDir);
@@ -4831,7 +4557,7 @@ var make3 = {
4831
4557
  const planId = generatePlanId(existingPlans + 1);
4832
4558
  const planPath = getPlanPath(sessionId, planId);
4833
4559
  const fullPlan = { ...plan, id: planId };
4834
- yield* Effect12.tryPromise({
4560
+ yield* Effect9.tryPromise({
4835
4561
  try: () => writeFile2(planPath, serializePlan(fullPlan), "utf-8"),
4836
4562
  catch: (error) => new PlanStoreError({
4837
4563
  message: `Failed to write plan file: ${planPath}`,
@@ -4841,10 +4567,10 @@ var make3 = {
4841
4567
  });
4842
4568
  return planId;
4843
4569
  }),
4844
- load: (planId, sessionId) => Effect12.gen(function* () {
4570
+ load: (planId, sessionId) => Effect9.gen(function* () {
4845
4571
  if (sessionId) {
4846
4572
  const planPath = getPlanPath(sessionId, planId);
4847
- const content = yield* Effect12.tryPromise({
4573
+ const content = yield* Effect9.tryPromise({
4848
4574
  try: () => readFile3(planPath, "utf-8"),
4849
4575
  catch: (error) => new PlanStoreError({
4850
4576
  message: `Failed to read plan file: ${planPath}`,
@@ -4854,7 +4580,7 @@ var make3 = {
4854
4580
  });
4855
4581
  return yield* deserializePlan(content, planId);
4856
4582
  }
4857
- const sessionDirs = yield* Effect12.tryPromise({
4583
+ const sessionDirs = yield* Effect9.tryPromise({
4858
4584
  try: async () => {
4859
4585
  const plansDir = join3(process.cwd(), PLANS_DIR2);
4860
4586
  const dirs = await readdir(plansDir);
@@ -4868,7 +4594,7 @@ var make3 = {
4868
4594
  });
4869
4595
  for (const sid of sessionDirs) {
4870
4596
  const planPath = getPlanPath(sid, planId);
4871
- const exists = yield* Effect12.tryPromise({
4597
+ const exists = yield* Effect9.tryPromise({
4872
4598
  try: async () => {
4873
4599
  await access2(planPath);
4874
4600
  return true;
@@ -4877,9 +4603,9 @@ var make3 = {
4877
4603
  message: "File not found",
4878
4604
  operation: "load"
4879
4605
  })
4880
- }).pipe(Effect12.orElseSucceed(() => false));
4606
+ }).pipe(Effect9.orElseSucceed(() => false));
4881
4607
  if (exists) {
4882
- const content = yield* Effect12.tryPromise({
4608
+ const content = yield* Effect9.tryPromise({
4883
4609
  try: () => readFile3(planPath, "utf-8"),
4884
4610
  catch: (error) => new PlanStoreError({
4885
4611
  message: `Failed to read plan file: ${planPath}`,
@@ -4890,16 +4616,16 @@ var make3 = {
4890
4616
  return yield* deserializePlan(content, planId);
4891
4617
  }
4892
4618
  }
4893
- return yield* Effect12.fail(
4619
+ return yield* Effect9.fail(
4894
4620
  new PlanStoreError({
4895
4621
  message: `Plan not found: ${planId}`,
4896
4622
  operation: "load"
4897
4623
  })
4898
4624
  );
4899
4625
  }),
4900
- update: (planId, plan) => Effect12.gen(function* () {
4626
+ update: (planId, plan) => Effect9.gen(function* () {
4901
4627
  const planPath = getPlanPath(plan.sessionId, planId);
4902
- yield* Effect12.tryPromise({
4628
+ yield* Effect9.tryPromise({
4903
4629
  try: () => writeFile2(planPath, serializePlan(plan), "utf-8"),
4904
4630
  catch: (error) => new PlanStoreError({
4905
4631
  message: `Failed to update plan file: ${planPath}`,
@@ -4908,9 +4634,9 @@ var make3 = {
4908
4634
  })
4909
4635
  });
4910
4636
  }),
4911
- list: (sessionId) => Effect12.gen(function* () {
4637
+ list: (sessionId) => Effect9.gen(function* () {
4912
4638
  const sessionDir = getSessionDir2(sessionId);
4913
- const files = yield* Effect12.tryPromise({
4639
+ const files = yield* Effect9.tryPromise({
4914
4640
  try: async () => {
4915
4641
  try {
4916
4642
  return await readdir(sessionDir);
@@ -4927,103 +4653,16 @@ var make3 = {
4927
4653
  return files.filter((f) => f.endsWith(".json")).map((f) => PlanId(f.replace(".json", "")));
4928
4654
  })
4929
4655
  };
4930
- var Live9 = Layer7.succeed(PlanStore, make3);
4656
+ var Live6 = Layer4.succeed(PlanStore, make3);
4931
4657
  var FileSystemPlan = {
4932
- Live: Live9
4933
- };
4934
-
4935
- // src/commands/code/layers/plan/memory.ts
4936
- init_esm_shims();
4937
- import { Effect as Effect13, Layer as Layer8, Ref as Ref5 } from "effect";
4938
- function createMemoryPlanStore(stateRef) {
4939
- return {
4940
- create: (sessionId, plan) => Effect13.gen(function* () {
4941
- const state = yield* Ref5.get(stateRef);
4942
- if (!state.has(sessionId)) {
4943
- state.set(sessionId, /* @__PURE__ */ new Map());
4944
- }
4945
- const sessionPlans = state.get(sessionId);
4946
- if (!sessionPlans) {
4947
- throw new Error("Session plans map should exist after set");
4948
- }
4949
- const planId = PlanId(`task-${sessionPlans.size + 1}`);
4950
- const fullPlan = { ...plan, id: planId };
4951
- sessionPlans.set(planId, fullPlan);
4952
- yield* Ref5.set(stateRef, state);
4953
- return planId;
4954
- }),
4955
- load: (planId, sessionId) => Effect13.gen(function* () {
4956
- const state = yield* Ref5.get(stateRef);
4957
- if (sessionId) {
4958
- const sessionPlans = state.get(sessionId);
4959
- const plan = sessionPlans?.get(planId);
4960
- if (plan) {
4961
- return plan;
4962
- }
4963
- return yield* Effect13.fail(
4964
- new PlanStoreError({
4965
- message: `Plan not found: ${planId}`,
4966
- operation: "load"
4967
- })
4968
- );
4969
- }
4970
- for (const sessionPlans of state.values()) {
4971
- const plan = sessionPlans.get(planId);
4972
- if (plan) {
4973
- return plan;
4974
- }
4975
- }
4976
- return yield* Effect13.fail(
4977
- new PlanStoreError({
4978
- message: `Plan not found: ${planId}`,
4979
- operation: "load"
4980
- })
4981
- );
4982
- }),
4983
- update: (planId, plan) => Effect13.gen(function* () {
4984
- const state = yield* Ref5.get(stateRef);
4985
- const sessionPlans = state.get(plan.sessionId);
4986
- if (!sessionPlans) {
4987
- return yield* Effect13.fail(
4988
- new PlanStoreError({
4989
- message: `Session not found: ${plan.sessionId}`,
4990
- operation: "update"
4991
- })
4992
- );
4993
- }
4994
- sessionPlans.set(planId, plan);
4995
- yield* Ref5.set(stateRef, state);
4996
- }),
4997
- list: (sessionId) => Effect13.gen(function* () {
4998
- const state = yield* Ref5.get(stateRef);
4999
- const sessionPlans = state.get(sessionId);
5000
- if (!sessionPlans) {
5001
- return [];
5002
- }
5003
- return Array.from(sessionPlans.keys());
5004
- })
5005
- };
5006
- }
5007
- function layer4() {
5008
- return Layer8.effect(
5009
- PlanStore,
5010
- Effect13.gen(function* () {
5011
- const stateRef = yield* Ref5.make(/* @__PURE__ */ new Map());
5012
- return createMemoryPlanStore(stateRef);
5013
- })
5014
- );
5015
- }
5016
- var Live10 = layer4();
5017
- var MemoryPlan = {
5018
- Live: Live10,
5019
- layer: layer4
4658
+ Live: Live6
5020
4659
  };
5021
4660
 
5022
4661
  // src/commands/code/layers/progress/file-system.ts
5023
4662
  init_esm_shims();
5024
4663
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
5025
4664
  import { join as join4 } from "path";
5026
- import { DateTime as DateTime3, Effect as Effect14, Layer as Layer9 } from "effect";
4665
+ import { DateTime as DateTime2, Effect as Effect10, Layer as Layer5 } from "effect";
5027
4666
 
5028
4667
  // src/commands/code/services/progress-store.ts
5029
4668
  init_esm_shims();
@@ -5034,27 +4673,30 @@ var ProgressStore = class extends Context5.Tag("@ferix/ProgressStore")() {
5034
4673
  // src/commands/code/layers/progress/file-system.ts
5035
4674
  var PLANS_DIR3 = ".ferix/plans";
5036
4675
  function ensureDir3(dirPath) {
5037
- return Effect14.tryPromise({
4676
+ return Effect10.tryPromise({
5038
4677
  try: () => mkdir4(dirPath, { recursive: true }),
5039
4678
  catch: (error) => new ProgressStoreError({
5040
4679
  message: `Failed to create directory: ${dirPath}`,
5041
4680
  operation: "append",
5042
4681
  cause: error
5043
4682
  })
5044
- }).pipe(Effect14.asVoid);
4683
+ }).pipe(Effect10.asVoid);
5045
4684
  }
5046
4685
  function getSessionDir3(sessionId) {
5047
4686
  return join4(process.cwd(), PLANS_DIR3, sessionId);
5048
4687
  }
5049
- function getProgressPath(sessionId) {
4688
+ function getProgressJsonPath(sessionId) {
5050
4689
  return join4(getSessionDir3(sessionId), "progress.json");
5051
4690
  }
4691
+ function getProgressMdPath(sessionId) {
4692
+ return join4(getSessionDir3(sessionId), "progress.md");
4693
+ }
5052
4694
  function serializeProgress(progress) {
5053
4695
  return JSON.stringify(progress, null, 2);
5054
4696
  }
5055
4697
  function deserializeProgress(json) {
5056
- return Effect14.gen(function* () {
5057
- const parsed = yield* Effect14.try({
4698
+ return Effect10.gen(function* () {
4699
+ const parsed = yield* Effect10.try({
5058
4700
  try: () => JSON.parse(json),
5059
4701
  catch: (error) => new ProgressStoreError({
5060
4702
  message: `Invalid JSON in progress file: ${String(error)}`,
@@ -5063,7 +4705,7 @@ function deserializeProgress(json) {
5063
4705
  })
5064
4706
  });
5065
4707
  const validated = yield* decodeProgressFile(parsed).pipe(
5066
- Effect14.mapError(
4708
+ Effect10.mapError(
5067
4709
  (error) => new ProgressStoreError({
5068
4710
  message: `Progress validation failed: ${String(error)}`,
5069
4711
  operation: "load",
@@ -5081,12 +4723,34 @@ function createEmptyProgress(sessionId, createdAt) {
5081
4723
  entries: []
5082
4724
  };
5083
4725
  }
4726
+ function writeProgressFiles(sessionId, progress, originalTask) {
4727
+ return Effect10.gen(function* () {
4728
+ const jsonPath = getProgressJsonPath(sessionId);
4729
+ const mdPath = getProgressMdPath(sessionId);
4730
+ yield* Effect10.tryPromise({
4731
+ try: () => writeFile3(jsonPath, serializeProgress(progress), "utf-8"),
4732
+ catch: (error) => new ProgressStoreError({
4733
+ message: `Failed to write progress.json: ${jsonPath}`,
4734
+ operation: "append",
4735
+ cause: error
4736
+ })
4737
+ });
4738
+ yield* Effect10.tryPromise({
4739
+ try: () => writeFile3(mdPath, formatProgressMd(progress, originalTask), "utf-8"),
4740
+ catch: (error) => new ProgressStoreError({
4741
+ message: `Failed to write progress.md: ${mdPath}`,
4742
+ operation: "append",
4743
+ cause: error
4744
+ })
4745
+ });
4746
+ });
4747
+ }
5084
4748
  var make4 = {
5085
- append: (sessionId, entry) => Effect14.gen(function* () {
4749
+ append: (sessionId, entry) => Effect10.gen(function* () {
5086
4750
  const sessionDir = getSessionDir3(sessionId);
5087
4751
  yield* ensureDir3(sessionDir);
5088
- const progressPath = getProgressPath(sessionId);
5089
- const existing = yield* Effect14.tryPromise({
4752
+ const progressPath = getProgressJsonPath(sessionId);
4753
+ const existing = yield* Effect10.tryPromise({
5090
4754
  try: async () => {
5091
4755
  try {
5092
4756
  const content = await readFile4(progressPath, "utf-8");
@@ -5104,7 +4768,7 @@ var make4 = {
5104
4768
  let progress;
5105
4769
  if (existing) {
5106
4770
  progress = yield* deserializeProgress(existing).pipe(
5107
- Effect14.mapError(
4771
+ Effect10.mapError(
5108
4772
  (err) => new ProgressStoreError({
5109
4773
  message: err.message,
5110
4774
  operation: "append",
@@ -5113,25 +4777,18 @@ var make4 = {
5113
4777
  )
5114
4778
  );
5115
4779
  } else {
5116
- const now = yield* DateTime3.now;
5117
- progress = createEmptyProgress(sessionId, DateTime3.formatIso(now));
4780
+ const now = yield* DateTime2.now;
4781
+ progress = createEmptyProgress(sessionId, DateTime2.formatIso(now));
5118
4782
  }
5119
4783
  const updatedProgress = {
5120
4784
  ...progress,
5121
4785
  entries: [...progress.entries, entry]
5122
4786
  };
5123
- yield* Effect14.tryPromise({
5124
- try: () => writeFile3(progressPath, serializeProgress(updatedProgress), "utf-8"),
5125
- catch: (error) => new ProgressStoreError({
5126
- message: `Failed to write progress file: ${progressPath}`,
5127
- operation: "append",
5128
- cause: error
5129
- })
5130
- });
4787
+ yield* writeProgressFiles(sessionId, updatedProgress);
5131
4788
  }),
5132
- load: (sessionId) => Effect14.gen(function* () {
5133
- const progressPath = getProgressPath(sessionId);
5134
- const content = yield* Effect14.tryPromise({
4789
+ load: (sessionId) => Effect10.gen(function* () {
4790
+ const progressPath = getProgressJsonPath(sessionId);
4791
+ const content = yield* Effect10.tryPromise({
5135
4792
  try: async () => {
5136
4793
  try {
5137
4794
  return await readFile4(progressPath, "utf-8");
@@ -5146,94 +4803,124 @@ var make4 = {
5146
4803
  })
5147
4804
  });
5148
4805
  if (content === null) {
5149
- const now = yield* DateTime3.now;
5150
- return createEmptyProgress(sessionId, DateTime3.formatIso(now));
4806
+ const now = yield* DateTime2.now;
4807
+ return createEmptyProgress(sessionId, DateTime2.formatIso(now));
5151
4808
  }
5152
4809
  return yield* deserializeProgress(content);
5153
4810
  }),
5154
- getRecent: (sessionId, count) => Effect14.gen(function* () {
4811
+ getRecent: (sessionId, count) => Effect10.gen(function* () {
5155
4812
  const progress = yield* make4.load(sessionId);
5156
4813
  const entries = progress.entries;
5157
4814
  return entries.slice(-count);
5158
4815
  })
5159
4816
  };
5160
- var Live11 = Layer9.succeed(ProgressStore, make4);
4817
+ var Live7 = Layer5.succeed(ProgressStore, make4);
5161
4818
  var FileSystemProgress = {
5162
- Live: Live11
4819
+ Live: Live7
5163
4820
  };
5164
4821
 
5165
- // src/commands/code/layers/progress/memory.ts
4822
+ // src/commands/code/layers/prompt/file-system.ts
5166
4823
  init_esm_shims();
5167
- import { DateTime as DateTime4, Effect as Effect15, Layer as Layer10, Ref as Ref6 } from "effect";
5168
- function createMemoryProgressStore(stateRef) {
5169
- return {
5170
- append: (sessionId, entry) => Effect15.gen(function* () {
5171
- const state = yield* Ref6.get(stateRef);
5172
- let progress = state.get(sessionId);
5173
- if (!progress) {
5174
- const now = yield* DateTime4.now;
5175
- progress = {
5176
- sessionId,
5177
- createdAt: DateTime4.formatIso(now),
5178
- entries: []
5179
- };
5180
- }
5181
- const updatedProgress = {
5182
- ...progress,
5183
- entries: [...progress.entries, entry]
5184
- };
5185
- state.set(sessionId, updatedProgress);
5186
- yield* Ref6.set(stateRef, state);
5187
- }),
5188
- load: (sessionId) => Effect15.gen(function* () {
5189
- const state = yield* Ref6.get(stateRef);
5190
- const progress = state.get(sessionId);
5191
- if (!progress) {
5192
- const now = yield* DateTime4.now;
5193
- return {
5194
- sessionId,
5195
- createdAt: DateTime4.formatIso(now),
5196
- entries: []
5197
- };
5198
- }
5199
- return progress;
5200
- }),
5201
- getRecent: (sessionId, count) => Effect15.gen(function* () {
5202
- const state = yield* Ref6.get(stateRef);
5203
- const progress = state.get(sessionId);
5204
- if (!progress) {
5205
- return [];
5206
- }
5207
- return progress.entries.slice(-count);
5208
- })
5209
- };
5210
- }
5211
- function layer5() {
5212
- return Layer10.effect(
5213
- ProgressStore,
5214
- Effect15.gen(function* () {
5215
- const stateRef = yield* Ref6.make(/* @__PURE__ */ new Map());
5216
- return createMemoryProgressStore(stateRef);
4824
+ import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
4825
+ import { dirname as dirname2, join as join5 } from "path";
4826
+ import { fileURLToPath as fileURLToPath2 } from "url";
4827
+ import { Effect as Effect11, Layer as Layer6 } from "effect";
4828
+
4829
+ // src/commands/code/services/prompt-store.ts
4830
+ init_esm_shims();
4831
+ import { Context as Context6 } from "effect";
4832
+ var PromptStore = class extends Context6.Tag("@ferix/PromptStore")() {
4833
+ };
4834
+
4835
+ // src/commands/code/layers/prompt/file-system.ts
4836
+ var PLANS_DIR4 = ".ferix/plans";
4837
+ var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
4838
+ var BUNDLED_TEMPLATE_PATH = join5(__dirname2, "../../templates/PROMPT.md");
4839
+ function ensureDir4(dirPath) {
4840
+ return Effect11.tryPromise({
4841
+ try: () => mkdir5(dirPath, { recursive: true }),
4842
+ catch: (error) => new PromptStoreError({
4843
+ message: `Failed to create directory: ${dirPath}`,
4844
+ operation: "copy",
4845
+ cause: error
5217
4846
  })
5218
- );
4847
+ }).pipe(Effect11.asVoid);
4848
+ }
4849
+ function getSessionDir4(sessionId) {
4850
+ return join5(process.cwd(), PLANS_DIR4, sessionId);
4851
+ }
4852
+ function getPromptPath(sessionId) {
4853
+ return join5(getSessionDir4(sessionId), "PROMPT.md");
5219
4854
  }
5220
- var Live12 = layer5();
5221
- var MemoryProgress = {
5222
- Live: Live12,
5223
- layer: layer5
4855
+ var cachedTemplate = null;
4856
+ var make5 = {
4857
+ copyTemplate: (sessionId) => Effect11.gen(function* () {
4858
+ const sessionDir = getSessionDir4(sessionId);
4859
+ yield* ensureDir4(sessionDir);
4860
+ const template = yield* make5.getBundledTemplate();
4861
+ const promptPath = getPromptPath(sessionId);
4862
+ yield* Effect11.tryPromise({
4863
+ try: () => writeFile4(promptPath, template, "utf-8"),
4864
+ catch: (error) => new PromptStoreError({
4865
+ message: `Failed to write PROMPT.md: ${promptPath}`,
4866
+ operation: "copy",
4867
+ cause: error
4868
+ })
4869
+ });
4870
+ }),
4871
+ read: (sessionId) => Effect11.gen(function* () {
4872
+ const promptPath = getPromptPath(sessionId);
4873
+ const sessionTemplate = yield* Effect11.tryPromise({
4874
+ try: async () => {
4875
+ try {
4876
+ return await readFile5(promptPath, "utf-8");
4877
+ } catch {
4878
+ return null;
4879
+ }
4880
+ },
4881
+ catch: (error) => new PromptStoreError({
4882
+ message: `Failed to read PROMPT.md: ${promptPath}`,
4883
+ operation: "read",
4884
+ cause: error
4885
+ })
4886
+ });
4887
+ if (sessionTemplate !== null) {
4888
+ return sessionTemplate;
4889
+ }
4890
+ return yield* make5.getBundledTemplate();
4891
+ }),
4892
+ getBundledTemplate: () => Effect11.gen(function* () {
4893
+ if (cachedTemplate !== null) {
4894
+ return cachedTemplate;
4895
+ }
4896
+ const template = yield* Effect11.tryPromise({
4897
+ try: () => readFile5(BUNDLED_TEMPLATE_PATH, "utf-8"),
4898
+ catch: (error) => new PromptStoreError({
4899
+ message: `Failed to read bundled PROMPT.md: ${BUNDLED_TEMPLATE_PATH}`,
4900
+ operation: "read",
4901
+ cause: error
4902
+ })
4903
+ });
4904
+ cachedTemplate = template;
4905
+ return template;
4906
+ })
4907
+ };
4908
+ var Live8 = Layer6.succeed(PromptStore, make5);
4909
+ var FileSystemPrompt = {
4910
+ Live: Live8
5224
4911
  };
5225
4912
 
5226
4913
  // src/commands/code/layers/session/file-system.ts
5227
4914
  init_esm_shims();
5228
- import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
5229
- import { join as join5 } from "path";
5230
- import { DateTime as DateTime5, Effect as Effect16, Layer as Layer11 } from "effect";
4915
+ import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
4916
+ import { join as join6 } from "path";
4917
+ import { DateTime as DateTime3, Effect as Effect12, Layer as Layer7 } from "effect";
5231
4918
  import { humanId } from "human-id";
5232
4919
 
5233
4920
  // src/commands/code/services/session-store.ts
5234
4921
  init_esm_shims();
5235
- import { Context as Context6 } from "effect";
5236
- var SessionStore = class extends Context6.Tag("@ferix/SessionStore")() {
4922
+ import { Context as Context7 } from "effect";
4923
+ var SessionStore = class extends Context7.Tag("@ferix/SessionStore")() {
5237
4924
  };
5238
4925
 
5239
4926
  // src/commands/code/layers/session/file-system.ts
@@ -5242,25 +4929,25 @@ function generateSessionId(timestampMs) {
5242
4929
  const id = humanId({ separator: "-", capitalize: false });
5243
4930
  return `${id}-${timestampMs}`;
5244
4931
  }
5245
- function ensureDir4(dirPath) {
5246
- return Effect16.tryPromise({
5247
- try: () => mkdir5(dirPath, { recursive: true }),
4932
+ function ensureDir5(dirPath) {
4933
+ return Effect12.tryPromise({
4934
+ try: () => mkdir6(dirPath, { recursive: true }),
5248
4935
  catch: (error) => new SessionStoreError({
5249
4936
  message: `Failed to create directory: ${dirPath}`,
5250
4937
  operation: "create",
5251
4938
  cause: error
5252
4939
  })
5253
- }).pipe(Effect16.asVoid);
4940
+ }).pipe(Effect12.asVoid);
5254
4941
  }
5255
4942
  function getSessionPath(sessionId) {
5256
- return join5(process.cwd(), SESSIONS_DIR, `${sessionId}.json`);
4943
+ return join6(process.cwd(), SESSIONS_DIR, `${sessionId}.json`);
5257
4944
  }
5258
4945
  function serializeSession(session) {
5259
4946
  return JSON.stringify(session, null, 2);
5260
4947
  }
5261
4948
  function deserializeSession(json) {
5262
- return Effect16.gen(function* () {
5263
- const parsed = yield* Effect16.try({
4949
+ return Effect12.gen(function* () {
4950
+ const parsed = yield* Effect12.try({
5264
4951
  try: () => JSON.parse(json),
5265
4952
  catch: (error) => new SessionStoreError({
5266
4953
  message: `Invalid JSON in session file: ${String(error)}`,
@@ -5269,7 +4956,7 @@ function deserializeSession(json) {
5269
4956
  })
5270
4957
  });
5271
4958
  const validated = yield* decodeSession(parsed).pipe(
5272
- Effect16.mapError(
4959
+ Effect12.mapError(
5273
4960
  (error) => new SessionStoreError({
5274
4961
  message: `Session validation failed: ${String(error)}`,
5275
4962
  operation: "get",
@@ -5280,23 +4967,23 @@ function deserializeSession(json) {
5280
4967
  return validated;
5281
4968
  });
5282
4969
  }
5283
- var make5 = {
5284
- create: (originalTask) => Effect16.gen(function* () {
5285
- const sessionsDir = join5(process.cwd(), SESSIONS_DIR);
5286
- yield* ensureDir4(sessionsDir);
5287
- const now = yield* DateTime5.now;
5288
- const timestampMs = DateTime5.toEpochMillis(now);
5289
- const sessionId = generateSessionId(timestampMs);
4970
+ var make6 = {
4971
+ create: (originalTask, providedSessionId) => Effect12.gen(function* () {
4972
+ const sessionsDir = join6(process.cwd(), SESSIONS_DIR);
4973
+ yield* ensureDir5(sessionsDir);
4974
+ const now = yield* DateTime3.now;
4975
+ const timestampMs = DateTime3.toEpochMillis(now);
4976
+ const sessionId = providedSessionId ?? generateSessionId(timestampMs);
5290
4977
  const session = {
5291
4978
  id: sessionId,
5292
- createdAt: DateTime5.formatIso(now),
4979
+ createdAt: DateTime3.formatIso(now),
5293
4980
  status: "active",
5294
4981
  originalTask,
5295
4982
  completedTasks: []
5296
4983
  };
5297
4984
  const sessionPath = getSessionPath(sessionId);
5298
- yield* Effect16.tryPromise({
5299
- try: () => writeFile4(sessionPath, serializeSession(session), "utf-8"),
4985
+ yield* Effect12.tryPromise({
4986
+ try: () => writeFile5(sessionPath, serializeSession(session), "utf-8"),
5300
4987
  catch: (error) => new SessionStoreError({
5301
4988
  message: `Failed to write session file: ${sessionPath}`,
5302
4989
  operation: "create",
@@ -5305,10 +4992,10 @@ var make5 = {
5305
4992
  });
5306
4993
  return session;
5307
4994
  }),
5308
- get: (sessionId) => Effect16.gen(function* () {
4995
+ get: (sessionId) => Effect12.gen(function* () {
5309
4996
  const sessionPath = getSessionPath(sessionId);
5310
- const content = yield* Effect16.tryPromise({
5311
- try: () => readFile5(sessionPath, "utf-8"),
4997
+ const content = yield* Effect12.tryPromise({
4998
+ try: () => readFile6(sessionPath, "utf-8"),
5312
4999
  catch: (error) => new SessionStoreError({
5313
5000
  message: `Failed to read session file: ${sessionPath}`,
5314
5001
  operation: "get",
@@ -5317,10 +5004,10 @@ var make5 = {
5317
5004
  });
5318
5005
  return yield* deserializeSession(content);
5319
5006
  }),
5320
- update: (sessionId, session) => Effect16.gen(function* () {
5007
+ update: (sessionId, session) => Effect12.gen(function* () {
5321
5008
  const sessionPath = getSessionPath(sessionId);
5322
- yield* Effect16.tryPromise({
5323
- try: () => writeFile4(sessionPath, serializeSession(session), "utf-8"),
5009
+ yield* Effect12.tryPromise({
5010
+ try: () => writeFile5(sessionPath, serializeSession(session), "utf-8"),
5324
5011
  catch: (error) => new SessionStoreError({
5325
5012
  message: `Failed to update session file: ${sessionPath}`,
5326
5013
  operation: "update",
@@ -5329,84 +5016,19 @@ var make5 = {
5329
5016
  });
5330
5017
  })
5331
5018
  };
5332
- var Live13 = Layer11.succeed(SessionStore, make5);
5019
+ var Live9 = Layer7.succeed(SessionStore, make6);
5333
5020
  var FileSystemSession = {
5334
- Live: Live13
5335
- };
5336
-
5337
- // src/commands/code/layers/session/memory.ts
5338
- init_esm_shims();
5339
- import { DateTime as DateTime6, Effect as Effect17, Layer as Layer12, Ref as Ref7 } from "effect";
5340
- function createMemorySessionStore(stateRef, counterRef) {
5341
- return {
5342
- create: (originalTask) => Effect17.gen(function* () {
5343
- const state = yield* Ref7.get(stateRef);
5344
- const counter = yield* Ref7.updateAndGet(counterRef, (n) => n + 1);
5345
- const sessionId = `test-session-${counter}`;
5346
- const now = yield* DateTime6.now;
5347
- const session = {
5348
- id: sessionId,
5349
- createdAt: DateTime6.formatIso(now),
5350
- status: "active",
5351
- originalTask,
5352
- completedTasks: []
5353
- };
5354
- state.set(sessionId, session);
5355
- yield* Ref7.set(stateRef, state);
5356
- return session;
5357
- }),
5358
- get: (sessionId) => Effect17.gen(function* () {
5359
- const state = yield* Ref7.get(stateRef);
5360
- const session = state.get(sessionId);
5361
- if (!session) {
5362
- return yield* Effect17.fail(
5363
- new SessionStoreError({
5364
- message: `Session not found: ${sessionId}`,
5365
- operation: "get"
5366
- })
5367
- );
5368
- }
5369
- return session;
5370
- }),
5371
- update: (sessionId, session) => Effect17.gen(function* () {
5372
- const state = yield* Ref7.get(stateRef);
5373
- if (!state.has(sessionId)) {
5374
- return yield* Effect17.fail(
5375
- new SessionStoreError({
5376
- message: `Session not found: ${sessionId}`,
5377
- operation: "update"
5378
- })
5379
- );
5380
- }
5381
- state.set(sessionId, session);
5382
- yield* Ref7.set(stateRef, state);
5383
- })
5384
- };
5385
- }
5386
- function layer6() {
5387
- return Layer12.effect(
5388
- SessionStore,
5389
- Effect17.gen(function* () {
5390
- const stateRef = yield* Ref7.make(/* @__PURE__ */ new Map());
5391
- const counterRef = yield* Ref7.make(0);
5392
- return createMemorySessionStore(stateRef, counterRef);
5393
- })
5394
- );
5395
- }
5396
- var Live14 = layer6();
5397
- var MemorySession = {
5398
- Live: Live14,
5399
- layer: layer6
5021
+ Live: Live9
5400
5022
  };
5401
5023
 
5402
5024
  // src/commands/code/layers/signal/ferix-parser.ts
5403
5025
  init_esm_shims();
5404
- import { Effect as Effect18, Layer as Layer13, Ref as Ref8 } from "effect";
5026
+ import { Effect as Effect13, Layer as Layer8, Ref as Ref3 } from "effect";
5405
5027
 
5406
5028
  // src/commands/code/services/signal-parser.ts
5407
5029
  init_esm_shims();
5408
- import { Context as Context7 } from "effect";
5409
- var SignalParser = class extends Context7.Tag("@ferix/SignalParser")() {
5030
+ import { Context as Context8 } from "effect";
5031
+ var SignalParser = class extends Context8.Tag("@ferix/SignalParser")() {
5410
5032
  };
5411
5033
 
5412
5034
  // src/commands/code/layers/signal/specs/index.ts
@@ -5414,7 +5036,7 @@ init_esm_shims();
5414
5036
 
5415
5037
  // src/commands/code/layers/signal/specs/check.ts
5416
5038
  init_esm_shims();
5417
- import { Either as Either6 } from "effect";
5039
+ import { Either as Either5 } from "effect";
5418
5040
 
5419
5041
  // src/commands/code/layers/signal/specs/registry.ts
5420
5042
  init_esm_shims();
@@ -5471,7 +5093,7 @@ var checkPassedSpec = {
5471
5093
  parse: (text) => {
5472
5094
  if (CHECK_PASSED.test(text)) {
5473
5095
  const result = createCheckPassedSignal({});
5474
- if (Either6.isRight(result)) {
5096
+ if (Either5.isRight(result)) {
5475
5097
  return [result.right];
5476
5098
  }
5477
5099
  }
@@ -5486,7 +5108,7 @@ var checkFailedSpec = {
5486
5108
  parse: (text) => {
5487
5109
  if (CHECK_FAILED.test(text)) {
5488
5110
  const result = createCheckFailedSignal({});
5489
- if (Either6.isRight(result)) {
5111
+ if (Either5.isRight(result)) {
5490
5112
  return [result.right];
5491
5113
  }
5492
5114
  }
@@ -5499,7 +5121,7 @@ signalSpecRegistry.register(checkFailedSpec);
5499
5121
 
5500
5122
  // src/commands/code/layers/signal/specs/criteria.ts
5501
5123
  init_esm_shims();
5502
- import { Either as Either7 } from "effect";
5124
+ import { Either as Either6 } from "effect";
5503
5125
  var CRITERIA_BLOCK = /<ferix:criteria task="(\d+)">([\s\S]*?)<\/ferix:criteria>/g;
5504
5126
  var CRITERION = /<criterion id="([^"]+)">([^<]+)<\/criterion>/g;
5505
5127
  var CRITERION_PASSED = /<ferix:criterion-passed id="([\d.c]+)"\/>/g;
@@ -5529,7 +5151,7 @@ var criteriaDefinedSpec = {
5529
5151
  taskId: match[1],
5530
5152
  criteria
5531
5153
  });
5532
- if (Either7.isRight(result)) {
5154
+ if (Either6.isRight(result)) {
5533
5155
  signals.push(result.right);
5534
5156
  }
5535
5157
  }
@@ -5547,7 +5169,7 @@ var criterionPassedSpec = {
5547
5169
  for (const m of text.matchAll(resetRegex(CRITERION_PASSED))) {
5548
5170
  if (m[1]) {
5549
5171
  const result = createCriterionPassedSignal({ criterionId: m[1] });
5550
- if (Either7.isRight(result)) {
5172
+ if (Either6.isRight(result)) {
5551
5173
  signals.push(result.right);
5552
5174
  }
5553
5175
  }
@@ -5568,7 +5190,7 @@ var criterionFailedSpec = {
5568
5190
  criterionId: m[1],
5569
5191
  reason: m[2] || "Unknown reason"
5570
5192
  });
5571
- if (Either7.isRight(result)) {
5193
+ if (Either6.isRight(result)) {
5572
5194
  signals.push(result.right);
5573
5195
  }
5574
5196
  }
@@ -5583,7 +5205,7 @@ signalSpecRegistry.register(criterionFailedSpec);
5583
5205
 
5584
5206
  // src/commands/code/layers/signal/specs/guardrail.ts
5585
5207
  init_esm_shims();
5586
- import { Either as Either8 } from "effect";
5208
+ import { Either as Either7 } from "effect";
5587
5209
  var GUARDRAIL = /<ferix:guardrail\s+severity="(warning|critical)"\s*>([\s\S]*?)<\/ferix:guardrail>/g;
5588
5210
  var PATTERN = /<pattern>([\s\S]*?)<\/pattern>/;
5589
5211
  var SIGN = /<sign>([\s\S]*?)<\/sign>/;
@@ -5613,7 +5235,7 @@ var guardrailSpec = {
5613
5235
  avoidance,
5614
5236
  severity
5615
5237
  });
5616
- if (Either8.isRight(result)) {
5238
+ if (Either7.isRight(result)) {
5617
5239
  signals.push(result.right);
5618
5240
  }
5619
5241
  }
@@ -5625,7 +5247,7 @@ signalSpecRegistry.register(guardrailSpec);
5625
5247
 
5626
5248
  // src/commands/code/layers/signal/specs/learning.ts
5627
5249
  init_esm_shims();
5628
- import { Either as Either9 } from "effect";
5250
+ import { Either as Either8 } from "effect";
5629
5251
  var LEARNING = /<ferix:learning(?:\s+category="(success|failure|optimization)")?\s*>([\s\S]*?)<\/ferix:learning>/g;
5630
5252
  var learningSpec = {
5631
5253
  tag: "Learning",
@@ -5641,7 +5263,7 @@ var learningSpec = {
5641
5263
  continue;
5642
5264
  }
5643
5265
  const result = createLearningSignal({ content, category });
5644
- if (Either9.isRight(result)) {
5266
+ if (Either8.isRight(result)) {
5645
5267
  signals.push(result.right);
5646
5268
  }
5647
5269
  }
@@ -5653,7 +5275,7 @@ signalSpecRegistry.register(learningSpec);
5653
5275
 
5654
5276
  // src/commands/code/layers/signal/specs/loop-complete.ts
5655
5277
  init_esm_shims();
5656
- import { Schema as S20 } from "effect";
5278
+ import { Schema as S19 } from "effect";
5657
5279
  var LOOP_COMPLETE = /<ferix:complete>/;
5658
5280
  var loopCompleteSpec = {
5659
5281
  tag: "LoopComplete",
@@ -5662,7 +5284,7 @@ var loopCompleteSpec = {
5662
5284
  parse: (text) => {
5663
5285
  if (LOOP_COMPLETE.test(text)) {
5664
5286
  const raw = { _tag: "LoopComplete" };
5665
- const result = S20.decodeUnknownEither(LoopCompleteSignalSchema)(raw);
5287
+ const result = S19.decodeUnknownEither(LoopCompleteSignalSchema)(raw);
5666
5288
  if (result._tag === "Right") {
5667
5289
  return [result.right];
5668
5290
  }
@@ -5675,7 +5297,7 @@ signalSpecRegistry.register(loopCompleteSpec);
5675
5297
 
5676
5298
  // src/commands/code/layers/signal/specs/phases.ts
5677
5299
  init_esm_shims();
5678
- import { Either as Either10 } from "effect";
5300
+ import { Either as Either9 } from "effect";
5679
5301
  var PHASES_BLOCK = /<ferix:phases task="(\d+)">([\s\S]*?)<\/ferix:phases>/;
5680
5302
  var PHASE = /<phase id="([\d.]+)">([^<]+)<\/phase>/g;
5681
5303
  var PHASE_START = /<ferix:phase-start id="([\d.]+)"\/>/g;
@@ -5704,7 +5326,7 @@ var phasesDefinedSpec = {
5704
5326
  return [];
5705
5327
  }
5706
5328
  const result = createPhasesDefinedSignal({ taskId: match[1], phases });
5707
- if (Either10.isRight(result)) {
5329
+ if (Either9.isRight(result)) {
5708
5330
  return [result.right];
5709
5331
  }
5710
5332
  return [];
@@ -5720,7 +5342,7 @@ var phaseStartedSpec = {
5720
5342
  for (const m of text.matchAll(resetRegex2(PHASE_START))) {
5721
5343
  if (m[1]) {
5722
5344
  const result = createPhaseStartedSignal({ phaseId: m[1] });
5723
- if (Either10.isRight(result)) {
5345
+ if (Either9.isRight(result)) {
5724
5346
  signals.push(result.right);
5725
5347
  }
5726
5348
  }
@@ -5738,7 +5360,7 @@ var phaseCompletedSpec = {
5738
5360
  for (const m of text.matchAll(resetRegex2(PHASE_DONE))) {
5739
5361
  if (m[1]) {
5740
5362
  const result = createPhaseCompletedSignal({ phaseId: m[1] });
5741
- if (Either10.isRight(result)) {
5363
+ if (Either9.isRight(result)) {
5742
5364
  signals.push(result.right);
5743
5365
  }
5744
5366
  }
@@ -5759,7 +5381,7 @@ var phaseFailedSpec = {
5759
5381
  phaseId: m[1],
5760
5382
  reason: m[2] || "Unknown reason"
5761
5383
  });
5762
- if (Either10.isRight(result)) {
5384
+ if (Either9.isRight(result)) {
5763
5385
  signals.push(result.right);
5764
5386
  }
5765
5387
  }
@@ -5775,7 +5397,7 @@ signalSpecRegistry.register(phaseFailedSpec);
5775
5397
 
5776
5398
  // src/commands/code/layers/signal/specs/review.ts
5777
5399
  init_esm_shims();
5778
- import { Schema as S21 } from "effect";
5400
+ import { Schema as S20 } from "effect";
5779
5401
  var REVIEW_COMPLETE = /<ferix:review-complete\/>/;
5780
5402
  var REVIEW_CHANGES = /<ferix:review-changes-made\/>/;
5781
5403
  var reviewCompleteSpec = {
@@ -5788,7 +5410,7 @@ var reviewCompleteSpec = {
5788
5410
  }
5789
5411
  const changesMade = REVIEW_CHANGES.test(text);
5790
5412
  const raw = { _tag: "ReviewComplete", changesMade };
5791
- const result = S21.decodeUnknownEither(ReviewCompleteSignalSchema)(raw);
5413
+ const result = S20.decodeUnknownEither(ReviewCompleteSignalSchema)(raw);
5792
5414
  if (result._tag === "Right") {
5793
5415
  return [result.right];
5794
5416
  }
@@ -5800,7 +5422,7 @@ signalSpecRegistry.register(reviewCompleteSpec);
5800
5422
 
5801
5423
  // src/commands/code/layers/signal/specs/session-name.ts
5802
5424
  init_esm_shims();
5803
- import { Either as Either11 } from "effect";
5425
+ import { Either as Either10 } from "effect";
5804
5426
  var SESSION_NAME = /<ferix:session-name>([\s\S]*?)<\/ferix:session-name>/g;
5805
5427
  function sanitizeSessionName(name) {
5806
5428
  return name.trim().toLowerCase().replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
@@ -5819,7 +5441,7 @@ var sessionNameSpec = {
5819
5441
  continue;
5820
5442
  }
5821
5443
  const result = createSessionNameDefinedSignal({ name });
5822
- if (Either11.isRight(result)) {
5444
+ if (Either10.isRight(result)) {
5823
5445
  signals.push(result.right);
5824
5446
  }
5825
5447
  }
@@ -5831,7 +5453,7 @@ signalSpecRegistry.register(sessionNameSpec);
5831
5453
 
5832
5454
  // src/commands/code/layers/signal/specs/task-complete.ts
5833
5455
  init_esm_shims();
5834
- import { Schema as S22 } from "effect";
5456
+ import { Schema as S21 } from "effect";
5835
5457
  var TASK_COMPLETE = /<ferix:task-complete id="(\d+)">([\s\S]*?)<\/ferix:task-complete>/;
5836
5458
  var SUMMARY = /<summary>([\s\S]*?)<\/summary>/;
5837
5459
  var FILES_MODIFIED = /<files-modified>([\s\S]*?)<\/files-modified>/;
@@ -5862,7 +5484,7 @@ var taskCompleteSpec = {
5862
5484
  filesModified: parseFileList(filesModifiedMatch?.[1]),
5863
5485
  filesCreated: parseFileList(filesCreatedMatch?.[1])
5864
5486
  };
5865
- const result = S22.decodeUnknownEither(TaskCompleteSignalSchema)(raw);
5487
+ const result = S21.decodeUnknownEither(TaskCompleteSignalSchema)(raw);
5866
5488
  if (result._tag === "Right") {
5867
5489
  return [result.right];
5868
5490
  }
@@ -5874,7 +5496,7 @@ signalSpecRegistry.register(taskCompleteSpec);
5874
5496
 
5875
5497
  // src/commands/code/layers/signal/specs/tasks.ts
5876
5498
  init_esm_shims();
5877
- import { Either as Either12 } from "effect";
5499
+ import { Either as Either11 } from "effect";
5878
5500
  var TASKS_BLOCK = /<ferix:tasks>([\s\S]*?)<\/ferix:tasks>/;
5879
5501
  var TASK = /<task id="(\d+)">([^<]+)<\/task>/g;
5880
5502
  function resetRegex3(pattern) {
@@ -5904,7 +5526,7 @@ var tasksDefinedSpec = {
5904
5526
  return [];
5905
5527
  }
5906
5528
  const result = createTasksDefinedSignal({ tasks });
5907
- if (Either12.isRight(result)) {
5529
+ if (Either11.isRight(result)) {
5908
5530
  return [result.right];
5909
5531
  }
5910
5532
  return [];
@@ -5916,20 +5538,20 @@ signalSpecRegistry.register(tasksDefinedSpec);
5916
5538
  // src/commands/code/layers/signal/ferix-parser.ts
5917
5539
  var MAX_BUFFER_SIZE = 1024 * 1024;
5918
5540
  function createAccumulatorImpl() {
5919
- return Effect18.gen(function* () {
5920
- const chunksRef = yield* Ref8.make([]);
5921
- const emittedRef = yield* Ref8.make(/* @__PURE__ */ new Set());
5922
- const feed = (text) => Effect18.gen(function* () {
5923
- const chunks = yield* Ref8.get(chunksRef);
5541
+ return Effect13.gen(function* () {
5542
+ const chunksRef = yield* Ref3.make([]);
5543
+ const emittedRef = yield* Ref3.make(/* @__PURE__ */ new Set());
5544
+ const feed = (text) => Effect13.gen(function* () {
5545
+ const chunks = yield* Ref3.get(chunksRef);
5924
5546
  chunks.push(text);
5925
5547
  const buffer = chunks.join("");
5926
5548
  if (buffer.length > MAX_BUFFER_SIZE) {
5927
- yield* Ref8.set(chunksRef, [
5549
+ yield* Ref3.set(chunksRef, [
5928
5550
  buffer.slice(buffer.length - MAX_BUFFER_SIZE)
5929
5551
  ]);
5930
5552
  }
5931
5553
  const signals = signalSpecRegistry.parseAll(buffer);
5932
- const emitted = yield* Ref8.get(emittedRef);
5554
+ const emitted = yield* Ref3.get(emittedRef);
5933
5555
  const newSignals = signals.filter((signal) => {
5934
5556
  const key = signalSpecRegistry.getSignalKey(signal);
5935
5557
  if (emitted.has(key)) {
@@ -5941,111 +5563,239 @@ function createAccumulatorImpl() {
5941
5563
  if (newSignals.length > 0) {
5942
5564
  const lastEndPos = signalSpecRegistry.findLastCompleteSignalEnd(buffer);
5943
5565
  if (lastEndPos > 0 && lastEndPos < buffer.length) {
5944
- yield* Ref8.set(chunksRef, [buffer.slice(lastEndPos)]);
5566
+ yield* Ref3.set(chunksRef, [buffer.slice(lastEndPos)]);
5945
5567
  }
5946
5568
  }
5947
- yield* Ref8.set(emittedRef, emitted);
5569
+ yield* Ref3.set(emittedRef, emitted);
5948
5570
  return newSignals;
5949
5571
  });
5950
- const flush = () => Effect18.gen(function* () {
5951
- const chunks = yield* Ref8.get(chunksRef);
5572
+ const flush = () => Effect13.gen(function* () {
5573
+ const chunks = yield* Ref3.get(chunksRef);
5952
5574
  const buffer = chunks.join("");
5953
- yield* Ref8.set(chunksRef, []);
5954
- const emitted = yield* Ref8.get(emittedRef);
5575
+ yield* Ref3.set(chunksRef, []);
5576
+ const emitted = yield* Ref3.get(emittedRef);
5955
5577
  const signals = signalSpecRegistry.parseAll(buffer);
5956
5578
  const result = signals.filter(
5957
5579
  (signal) => !emitted.has(signalSpecRegistry.getSignalKey(signal))
5958
5580
  );
5959
- yield* Ref8.set(emittedRef, /* @__PURE__ */ new Set());
5581
+ yield* Ref3.set(emittedRef, /* @__PURE__ */ new Set());
5960
5582
  return result;
5961
5583
  });
5962
5584
  return { feed, flush };
5963
5585
  });
5964
5586
  }
5965
- var make6 = {
5966
- parse: (text) => Effect18.succeed(signalSpecRegistry.parseAll(text)),
5587
+ var make7 = {
5588
+ parse: (text) => Effect13.succeed(signalSpecRegistry.parseAll(text)),
5967
5589
  createAccumulator: createAccumulatorImpl
5968
5590
  };
5969
- var Live15 = Layer13.succeed(SignalParser, make6);
5591
+ var Live10 = Layer8.succeed(SignalParser, make7);
5970
5592
  var FerixParser = {
5971
- Live: Live15
5593
+ Live: Live10
5594
+ };
5595
+
5596
+ // src/commands/code/layers/state/file-system.ts
5597
+ init_esm_shims();
5598
+ import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
5599
+ import { join as join7 } from "path";
5600
+ import { Effect as Effect14, Layer as Layer9 } from "effect";
5601
+
5602
+ // src/commands/code/services/state-store.ts
5603
+ init_esm_shims();
5604
+ import { Context as Context9 } from "effect";
5605
+ var StateStore = class extends Context9.Tag("@ferix/StateStore")() {
5606
+ };
5607
+
5608
+ // src/commands/code/layers/state/file-system.ts
5609
+ var PLANS_DIR5 = ".ferix/plans";
5610
+ function ensureDir6(dirPath) {
5611
+ return Effect14.tryPromise({
5612
+ try: () => mkdir7(dirPath, { recursive: true }),
5613
+ catch: (error) => new StateStoreError({
5614
+ message: `Failed to create directory: ${dirPath}`,
5615
+ operation: "write",
5616
+ cause: error
5617
+ })
5618
+ }).pipe(Effect14.asVoid);
5619
+ }
5620
+ function getSessionDir5(sessionId) {
5621
+ return join7(process.cwd(), PLANS_DIR5, sessionId);
5622
+ }
5623
+ function getStatePath(sessionId) {
5624
+ return join7(getSessionDir5(sessionId), "STATE.json");
5625
+ }
5626
+ function serializeState(state) {
5627
+ return JSON.stringify(state, null, 2);
5628
+ }
5629
+ function deserializeState(json) {
5630
+ return Effect14.gen(function* () {
5631
+ const parsed = yield* Effect14.try({
5632
+ try: () => JSON.parse(json),
5633
+ catch: (error) => new StateStoreError({
5634
+ message: `Invalid JSON in STATE.json: ${String(error)}`,
5635
+ operation: "read",
5636
+ cause: error
5637
+ })
5638
+ });
5639
+ const validated = yield* decodeSessionState(parsed).pipe(
5640
+ Effect14.mapError(
5641
+ (error) => new StateStoreError({
5642
+ message: `STATE.json validation failed: ${String(error)}`,
5643
+ operation: "read",
5644
+ cause: error
5645
+ })
5646
+ )
5647
+ );
5648
+ return validated;
5649
+ });
5650
+ }
5651
+ var make8 = {
5652
+ write: (sessionId, state) => Effect14.gen(function* () {
5653
+ const sessionDir = getSessionDir5(sessionId);
5654
+ yield* ensureDir6(sessionDir);
5655
+ const statePath = getStatePath(sessionId);
5656
+ yield* Effect14.tryPromise({
5657
+ try: () => writeFile6(statePath, serializeState(state), "utf-8"),
5658
+ catch: (error) => new StateStoreError({
5659
+ message: `Failed to write STATE.json: ${statePath}`,
5660
+ operation: "write",
5661
+ cause: error
5662
+ })
5663
+ });
5664
+ }),
5665
+ read: (sessionId) => Effect14.gen(function* () {
5666
+ const statePath = getStatePath(sessionId);
5667
+ const content = yield* Effect14.tryPromise({
5668
+ try: () => readFile7(statePath, "utf-8"),
5669
+ catch: (error) => new StateStoreError({
5670
+ message: `Failed to read STATE.json: ${statePath}`,
5671
+ operation: "read",
5672
+ cause: error
5673
+ })
5674
+ });
5675
+ return yield* deserializeState(content);
5676
+ })
5677
+ };
5678
+ var Live11 = Layer9.succeed(StateStore, make8);
5679
+ var FileSystemState = {
5680
+ Live: Live11
5972
5681
  };
5973
5682
 
5683
+ // src/commands/code/layers/logger.ts
5684
+ init_esm_shims();
5685
+ import {
5686
+ createWriteStream,
5687
+ existsSync,
5688
+ mkdirSync
5689
+ } from "fs";
5690
+ import { join as join8 } from "path";
5691
+ import { Layer as Layer10, Logger, LogLevel } from "effect";
5692
+ var LOGS_DIR = ".ferix/logs";
5693
+ function ensureLogsDir() {
5694
+ const logsDir = join8(process.cwd(), LOGS_DIR);
5695
+ if (!existsSync(logsDir)) {
5696
+ mkdirSync(logsDir, { recursive: true });
5697
+ }
5698
+ }
5699
+ function formatAnnotations(annotations) {
5700
+ const parts = [];
5701
+ for (const [key, value] of annotations) {
5702
+ parts.push(`${key}=${JSON.stringify(value)}`);
5703
+ }
5704
+ return parts.join(" ");
5705
+ }
5706
+ function createFileLogger(logStream) {
5707
+ return Logger.make(({ logLevel, message, date, annotations }) => {
5708
+ const annotationsStr = formatAnnotations(annotations);
5709
+ const messageStr = typeof message === "string" ? message : JSON.stringify(message);
5710
+ const entry = `timestamp=${date.toISOString()} level=${logLevel.label} message=${JSON.stringify(messageStr)}${annotationsStr ? ` ${annotationsStr}` : ""}`;
5711
+ logStream.write(`${entry}
5712
+ `);
5713
+ });
5714
+ }
5715
+ function createLoggerLayer(debug, sessionId) {
5716
+ if (!debug) {
5717
+ return Layer10.empty;
5718
+ }
5719
+ ensureLogsDir();
5720
+ const logPath = join8(process.cwd(), LOGS_DIR, `${sessionId}.log`);
5721
+ const logStream = createWriteStream(logPath, { flags: "a" });
5722
+ const fileLogger = createFileLogger(logStream);
5723
+ return Layer10.merge(
5724
+ Logger.minimumLogLevel(LogLevel.Debug),
5725
+ Logger.replace(Logger.defaultLogger, fileLogger)
5726
+ );
5727
+ }
5728
+
5974
5729
  // src/commands/code/layers/index.ts
5975
- var ProductionLayers = Layer14.mergeAll(
5730
+ var ProductionLayers = Layer11.mergeAll(
5976
5731
  ClaudeCLI.Live,
5977
5732
  FerixParser.Live,
5978
5733
  FileSystemPlan.Live,
5979
5734
  FileSystemSession.Live,
5980
5735
  FileSystemProgress.Live,
5981
5736
  FileSystemGuardrails.Live,
5982
- FileSystemGit.Live
5737
+ FileSystemGit.Live,
5738
+ FileSystemState.Live,
5739
+ FileSystemPrompt.Live
5983
5740
  );
5984
5741
  function createProductionLayers(provider = "claude") {
5985
5742
  const llmLayer = createProviderLayer2(provider);
5986
- return Layer14.mergeAll(
5743
+ return Layer11.mergeAll(
5987
5744
  llmLayer,
5988
5745
  FerixParser.Live,
5989
5746
  FileSystemPlan.Live,
5990
5747
  FileSystemSession.Live,
5991
5748
  FileSystemProgress.Live,
5992
5749
  FileSystemGuardrails.Live,
5993
- FileSystemGit.Live
5750
+ FileSystemGit.Live,
5751
+ FileSystemState.Live,
5752
+ FileSystemPrompt.Live
5994
5753
  );
5995
5754
  }
5996
- var TestLayers = Layer14.mergeAll(
5997
- Mock.Live,
5998
- FerixParser.Live,
5999
- MemoryPlan.Live,
6000
- MemorySession.Live,
6001
- MemoryProgress.Live,
6002
- MemoryGuardrails.Live,
6003
- MemoryGit.Live
6004
- );
6005
5755
 
6006
5756
  // src/commands/code/orchestrator/index.ts
6007
5757
  init_esm_shims();
6008
5758
 
6009
5759
  // src/commands/code/orchestrator/loop.ts
6010
5760
  init_esm_shims();
6011
- import { DateTime as DateTime10, Effect as Effect23, Option, pipe as pipe3, Ref as Ref12, Stream as Stream9 } from "effect";
5761
+ import { DateTime as DateTime7, Effect as Effect19, Option, pipe as pipe3, Ref as Ref7, Stream as Stream8 } from "effect";
6012
5762
 
6013
5763
  // src/commands/code/orchestrator/discovery.ts
6014
5764
  init_esm_shims();
6015
- import { DateTime as DateTime8, Effect as Effect21, pipe, Ref as Ref10, Stream as Stream7 } from "effect";
5765
+ import { DateTime as DateTime5, Effect as Effect17, pipe, Ref as Ref5, Stream as Stream6 } from "effect";
6016
5766
 
6017
5767
  // src/commands/code/layers/plan/task-generation.ts
6018
5768
  init_esm_shims();
6019
- import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
6020
- import { join as join6 } from "path";
6021
- import { Effect as Effect19 } from "effect";
6022
- var PLANS_DIR4 = ".ferix/plans";
6023
- function ensureDir5(dirPath) {
6024
- return Effect19.tryPromise({
6025
- try: () => mkdir6(dirPath, { recursive: true }),
5769
+ import { mkdir as mkdir8, writeFile as writeFile7 } from "fs/promises";
5770
+ import { join as join9 } from "path";
5771
+ import { Effect as Effect15 } from "effect";
5772
+ var PLANS_DIR6 = ".ferix/plans";
5773
+ function ensureDir7(dirPath) {
5774
+ return Effect15.tryPromise({
5775
+ try: () => mkdir8(dirPath, { recursive: true }),
6026
5776
  catch: (error) => new PlanStoreError({
6027
5777
  message: `Failed to create directory: ${dirPath}`,
6028
5778
  operation: "create",
6029
5779
  cause: error
6030
5780
  })
6031
- }).pipe(Effect19.asVoid);
6032
- }
6033
- function getSessionDir4(sessionId) {
6034
- return join6(process.cwd(), PLANS_DIR4, sessionId);
6035
- }
6036
- function getTasksMdPath(sessionId) {
6037
- return join6(getSessionDir4(sessionId), "tasks.md");
6038
- }
6039
- function writeTasksMd(sessionId, tasks) {
6040
- return Effect19.gen(function* () {
6041
- const sessionDir = getSessionDir4(sessionId);
6042
- yield* ensureDir5(sessionDir);
6043
- const tasksMdPath = getTasksMdPath(sessionId);
6044
- const content = formatTasksMd(tasks);
6045
- yield* Effect19.tryPromise({
6046
- try: () => writeFile5(tasksMdPath, content, "utf-8"),
5781
+ }).pipe(Effect15.asVoid);
5782
+ }
5783
+ function getSessionDir6(sessionId) {
5784
+ return join9(process.cwd(), PLANS_DIR6, sessionId);
5785
+ }
5786
+ function getTasksJsonPath(sessionId) {
5787
+ return join9(getSessionDir6(sessionId), "tasks.json");
5788
+ }
5789
+ function writeTasksJson(sessionId, tasksFile) {
5790
+ return Effect15.gen(function* () {
5791
+ const sessionDir = getSessionDir6(sessionId);
5792
+ yield* ensureDir7(sessionDir);
5793
+ const tasksJsonPath = getTasksJsonPath(sessionId);
5794
+ const content = formatTasksJson(tasksFile);
5795
+ yield* Effect15.tryPromise({
5796
+ try: () => writeFile7(tasksJsonPath, content, "utf-8"),
6047
5797
  catch: (error) => new PlanStoreError({
6048
- message: `Failed to write tasks.md: ${tasksMdPath}`,
5798
+ message: `Failed to write tasks.json: ${tasksJsonPath}`,
6049
5799
  operation: "create",
6050
5800
  cause: error
6051
5801
  })
@@ -6234,7 +5984,7 @@ function mapSignalToDomain(signal, context) {
6234
5984
 
6235
5985
  // src/commands/code/orchestrator/plan-updates.ts
6236
5986
  init_esm_shims();
6237
- import { DateTime as DateTime7, Effect as Effect20, Ref as Ref9 } from "effect";
5987
+ import { DateTime as DateTime4, Effect as Effect16, Ref as Ref4 } from "effect";
6238
5988
 
6239
5989
  // src/commands/code/orchestrator/plan-updates/index.ts
6240
5990
  init_esm_shims();
@@ -6556,9 +6306,9 @@ function persistPlanUpdate(planStore, plan, operation) {
6556
6306
  tasks: plan.tasks
6557
6307
  }) : planStore.update(plan.id, plan);
6558
6308
  return storeOp.pipe(
6559
- Effect20.map(() => null),
6560
- Effect20.catchAll(
6561
- (error) => Effect20.succeed({
6309
+ Effect16.map(() => null),
6310
+ Effect16.catchAll(
6311
+ (error) => Effect16.succeed({
6562
6312
  _tag: "PlanUpdateFailed",
6563
6313
  operation,
6564
6314
  error: error.message,
@@ -6568,10 +6318,10 @@ function persistPlanUpdate(planStore, plan, operation) {
6568
6318
  );
6569
6319
  }
6570
6320
  function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessionId, originalTask) {
6571
- return Effect20.gen(function* () {
6572
- const currentPlan = yield* Ref9.get(currentPlanRef);
6573
- const now = yield* DateTime7.now;
6574
- const timestamp = DateTime7.formatIso(now);
6321
+ return Effect16.gen(function* () {
6322
+ const currentPlan = yield* Ref4.get(currentPlanRef);
6323
+ const now = yield* DateTime4.now;
6324
+ const timestamp = DateTime4.formatIso(now);
6575
6325
  const updateResult = computePlanUpdate(signal, currentPlan, {
6576
6326
  sessionId,
6577
6327
  originalTask,
@@ -6581,8 +6331,8 @@ function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessi
6581
6331
  return [];
6582
6332
  }
6583
6333
  const { plan, operation, eventTag } = updateResult;
6584
- yield* Ref9.set(currentPlanRef, plan);
6585
- yield* Ref9.update(persistenceStateRef, (state) => ({
6334
+ yield* Ref4.set(currentPlanRef, plan);
6335
+ yield* Ref4.update(persistenceStateRef, (state) => ({
6586
6336
  dirty: true,
6587
6337
  pendingOperation: state.pendingOperation === "create" ? "create" : operation
6588
6338
  }));
@@ -6590,12 +6340,12 @@ function updatePlanFromSignal(currentPlanRef, persistenceStateRef, signal, sessi
6590
6340
  });
6591
6341
  }
6592
6342
  function flushPlanPersistence(planStore, currentPlanRef, persistenceStateRef) {
6593
- return Effect20.gen(function* () {
6594
- const state = yield* Ref9.get(persistenceStateRef);
6343
+ return Effect16.gen(function* () {
6344
+ const state = yield* Ref4.get(persistenceStateRef);
6595
6345
  if (!(state.dirty && state.pendingOperation)) {
6596
6346
  return [];
6597
6347
  }
6598
- const plan = yield* Ref9.get(currentPlanRef);
6348
+ const plan = yield* Ref4.get(currentPlanRef);
6599
6349
  if (!plan) {
6600
6350
  return [];
6601
6351
  }
@@ -6608,7 +6358,7 @@ function flushPlanPersistence(planStore, currentPlanRef, persistenceStateRef) {
6608
6358
  if (failureEvent) {
6609
6359
  events.push(failureEvent);
6610
6360
  }
6611
- yield* Ref9.set(persistenceStateRef, {
6361
+ yield* Ref4.set(persistenceStateRef, {
6612
6362
  dirty: false,
6613
6363
  pendingOperation: null
6614
6364
  });
@@ -6678,7 +6428,7 @@ var DISCOVERY_SYSTEM_PROMPT = `You are in the DISCOVERY phase of a ralph loop -
6678
6428
 
6679
6429
  Your goal is to:
6680
6430
  1. Generate a short, descriptive name for this session
6681
- 2. Analyze the task and break it into logical subtasks
6431
+ 2. Analyze the task and break it into SMALL, GRANULAR subtasks
6682
6432
 
6683
6433
  Your output must include these signals that the orchestrator will parse.
6684
6434
  These signals MUST appear on their own lines, not inside code blocks.
@@ -6700,6 +6450,21 @@ Guidelines for session name:
6700
6450
  <task id="2">Brief description of second task</task>
6701
6451
  </ferix:tasks>
6702
6452
 
6453
+ ## Task Granularity Rules (CRITICAL)
6454
+
6455
+ Apply the **"one sentence without 'and'" test**:
6456
+ - If describing a task requires "and" to connect unrelated functions, split it
6457
+ - Good: "Add login endpoint that validates credentials and returns JWT"
6458
+ - Bad: "Handle authentication, user profiles, and billing"
6459
+
6460
+ Each task MUST be:
6461
+ - Small enough to complete in ONE context window
6462
+ - Testable in isolation with automated checks
6463
+ - A single logical unit of work
6464
+
6465
+ For a typical feature, create 5-15 tasks.
6466
+ For complex projects, create 50-200+ discrete tasks.
6467
+
6703
6468
  ## CRITICAL: Task Exclusions
6704
6469
 
6705
6470
  Do NOT create tasks for any of the following - these are handled automatically by the orchestrator:
@@ -6911,15 +6676,51 @@ function areAllTasksComplete(plan) {
6911
6676
  }
6912
6677
  return plan.tasks.every((t) => t.status === "done" || t.status === "skipped");
6913
6678
  }
6679
+ function buildSessionState(config, iteration, sessionId, plan, recentProgress = []) {
6680
+ const currentTask = plan?.tasks.find(
6681
+ (t) => t.status === "in_progress" || t.status === "pending"
6682
+ );
6683
+ const taskSummary = plan ? {
6684
+ total: plan.tasks.length,
6685
+ done: plan.tasks.filter((t) => t.status === "done").length,
6686
+ inProgress: plan.tasks.filter((t) => t.status === "in_progress").length,
6687
+ pending: plan.tasks.filter(
6688
+ (t) => t.status === "pending" || t.status === "planning"
6689
+ ).length
6690
+ } : { total: 0, done: 0, inProgress: 0, pending: 0 };
6691
+ return {
6692
+ sessionId,
6693
+ originalTask: config.task,
6694
+ iteration,
6695
+ maxIterations: config.maxIterations,
6696
+ taskSummary,
6697
+ currentTask: currentTask ? {
6698
+ id: currentTask.id,
6699
+ title: currentTask.title,
6700
+ description: currentTask.description,
6701
+ phases: currentTask.phases.map((p) => ({
6702
+ id: p.id,
6703
+ description: p.description,
6704
+ status: p.status
6705
+ })),
6706
+ criteria: currentTask.criteria.map((c) => ({
6707
+ id: c.id,
6708
+ description: c.description,
6709
+ status: c.status
6710
+ }))
6711
+ } : null,
6712
+ recentProgress
6713
+ };
6714
+ }
6914
6715
 
6915
6716
  // src/commands/code/orchestrator/discovery.ts
6916
6717
  function processTextSignals(signalParser, text, context) {
6917
- return Effect21.gen(function* () {
6718
+ return Effect17.gen(function* () {
6918
6719
  const events = [];
6919
6720
  const parsedSignals = [];
6920
6721
  const signals = yield* signalParser.parse(text).pipe(
6921
- Effect21.tapError(
6922
- (error) => Effect21.logDebug(
6722
+ Effect17.tapError(
6723
+ (error) => Effect17.logDebug(
6923
6724
  "Signal parsing failed, continuing with empty signals",
6924
6725
  {
6925
6726
  error: String(error),
@@ -6927,7 +6728,7 @@ function processTextSignals(signalParser, text, context) {
6927
6728
  }
6928
6729
  )
6929
6730
  ),
6930
- Effect21.orElseSucceed(() => [])
6731
+ Effect17.orElseSucceed(() => [])
6931
6732
  );
6932
6733
  for (const signal of signals) {
6933
6734
  events.push(mapSignalToDomain(signal, context));
@@ -6937,7 +6738,7 @@ function processTextSignals(signalParser, text, context) {
6937
6738
  });
6938
6739
  }
6939
6740
  function processLLMEvent(signalParser, llmEvent, context) {
6940
- return Effect21.gen(function* () {
6741
+ return Effect17.gen(function* () {
6941
6742
  const domainEvent = mapLLMEventToDomain(llmEvent, context);
6942
6743
  const events = [domainEvent];
6943
6744
  const allSignals = [];
@@ -6973,23 +6774,29 @@ function mapTaskStatus(status) {
6973
6774
  }
6974
6775
  return "pending";
6975
6776
  }
6976
- function planTasksToGeneratedTasks(plan) {
6977
- return plan.tasks.map((task) => ({
6978
- id: task.id,
6979
- title: task.title,
6980
- status: mapTaskStatus(task.status)
6981
- }));
6777
+ function planToTasksFile(plan, sessionId, originalTask) {
6778
+ return {
6779
+ sessionId,
6780
+ originalTask,
6781
+ tasks: plan.tasks.map((task) => ({
6782
+ id: task.id,
6783
+ title: task.title,
6784
+ description: task.description,
6785
+ status: mapTaskStatus(task.status),
6786
+ steps: task.phases.map((p) => p.description)
6787
+ }))
6788
+ };
6982
6789
  }
6983
- function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, config, sessionId, worktreePath, onSessionName) {
6984
- return Stream7.unwrap(
6985
- Effect21.gen(function* () {
6986
- const startTimeUtc = yield* DateTime8.now;
6987
- const startTime = DateTime8.toEpochMillis(startTimeUtc);
6988
- const persistenceStateRef = yield* Ref10.make({
6790
+ function createDiscoveryStream(llm, signalParser, planStore, stateStore, promptStore, progressStore, currentPlanRef, config, sessionId, worktreePath, onSessionName) {
6791
+ return Stream6.unwrap(
6792
+ Effect17.gen(function* () {
6793
+ const startTimeUtc = yield* DateTime5.now;
6794
+ const startTime = DateTime5.toEpochMillis(startTimeUtc);
6795
+ const persistenceStateRef = yield* Ref5.make({
6989
6796
  dirty: false,
6990
6797
  pendingOperation: null
6991
6798
  });
6992
- const sessionNameRef = yield* Ref10.make(void 0);
6799
+ const sessionNameRef = yield* Ref5.make(void 0);
6993
6800
  const discoveryStarted = {
6994
6801
  _tag: "DiscoveryStarted",
6995
6802
  timestamp: startTime
@@ -7000,20 +6807,20 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
7000
6807
  input: {}
7001
6808
  };
7002
6809
  const prompt = buildDiscoveryPrompt(config);
7003
- const llmStream = llm.execute(prompt, worktreePath ? { cwd: worktreePath } : void 0).pipe(
7004
- Stream7.mapError(
6810
+ const llmStream = llm.execute(prompt, { cwd: worktreePath, yolo: config.yolo }).pipe(
6811
+ Stream6.mapError(
7005
6812
  (e) => new OrchestratorError({
7006
6813
  message: `LLM execution failed during discovery: ${String(e)}`,
7007
6814
  phase: "discovery",
7008
6815
  cause: e
7009
6816
  })
7010
6817
  ),
7011
- Stream7.flatMap(
7012
- (llmEvent) => Stream7.unwrap(
7013
- Effect21.gen(function* () {
7014
- const now = yield* DateTime8.now;
6818
+ Stream6.flatMap(
6819
+ (llmEvent) => Stream6.unwrap(
6820
+ Effect17.gen(function* () {
6821
+ const now = yield* DateTime5.now;
7015
6822
  const context = {
7016
- timestamp: DateTime8.toEpochMillis(now)
6823
+ timestamp: DateTime5.toEpochMillis(now)
7017
6824
  };
7018
6825
  const result = yield* processLLMEvent(
7019
6826
  signalParser,
@@ -7023,7 +6830,7 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
7023
6830
  const events = [...result.events];
7024
6831
  for (const signal of result.signals) {
7025
6832
  if (signal._tag === "SessionNameDefined") {
7026
- yield* Ref10.set(sessionNameRef, signal.name);
6833
+ yield* Ref5.set(sessionNameRef, signal.name);
7027
6834
  }
7028
6835
  const planEvents = yield* updatePlanFromSignal(
7029
6836
  currentPlanRef,
@@ -7034,13 +6841,13 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
7034
6841
  );
7035
6842
  events.push(...planEvents);
7036
6843
  }
7037
- return Stream7.fromIterable(events);
6844
+ return Stream6.fromIterable(events);
7038
6845
  })
7039
6846
  )
7040
6847
  ),
7041
6848
  // Convert LLM errors to LoopFailed events
7042
- Stream7.catchAll(
7043
- (error) => Stream7.succeed({
6849
+ Stream6.catchAll(
6850
+ (error) => Stream6.succeed({
7044
6851
  _tag: "LoopFailed",
7045
6852
  error: {
7046
6853
  message: error.message,
@@ -7049,35 +6856,73 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
7049
6856
  })
7050
6857
  )
7051
6858
  );
7052
- const completionStream = Stream7.fromEffect(
7053
- Effect21.gen(function* () {
6859
+ const completionStream = Stream6.fromEffect(
6860
+ Effect17.gen(function* () {
7054
6861
  const persistEvents = yield* flushPlanPersistence(
7055
6862
  planStore,
7056
6863
  currentPlanRef,
7057
6864
  persistenceStateRef
7058
6865
  );
7059
- const plan = yield* Ref10.get(currentPlanRef);
6866
+ const plan = yield* Ref5.get(currentPlanRef);
7060
6867
  const taskCount = plan?.tasks.length ?? 0;
6868
+ yield* promptStore.copyTemplate(sessionId).pipe(
6869
+ Effect17.tapError(
6870
+ (error) => Effect17.logDebug("Failed to copy PROMPT.md, continuing", {
6871
+ error: String(error)
6872
+ })
6873
+ ),
6874
+ Effect17.orElseSucceed(() => void 0)
6875
+ );
7061
6876
  if (plan && plan.tasks.length > 0) {
7062
- const generatedTasks = planTasksToGeneratedTasks(plan);
7063
- yield* writeTasksMd(sessionId, generatedTasks).pipe(
7064
- Effect21.tapError(
7065
- (error) => Effect21.logDebug("Failed to write tasks.md, continuing", {
6877
+ const tasksFile = planToTasksFile(plan, sessionId, config.task);
6878
+ yield* writeTasksJson(sessionId, tasksFile).pipe(
6879
+ Effect17.tapError(
6880
+ (error) => Effect17.logDebug("Failed to write tasks.json, continuing", {
7066
6881
  error: String(error)
7067
6882
  })
7068
6883
  ),
7069
- Effect21.orElseSucceed(() => void 0)
6884
+ Effect17.orElseSucceed(() => void 0)
6885
+ );
6886
+ const recentEntries = yield* progressStore.getRecent(sessionId, 5).pipe(
6887
+ Effect17.tapError(
6888
+ (error) => Effect17.logDebug(
6889
+ "Failed to get recent progress, continuing",
6890
+ {
6891
+ error: String(error)
6892
+ }
6893
+ )
6894
+ ),
6895
+ Effect17.orElseSucceed(() => [])
6896
+ );
6897
+ const recentProgress = recentEntries.map(
6898
+ (entry) => `[${entry.action}] Task ${entry.taskId}: ${entry.summary}`
6899
+ );
6900
+ const initialState = buildSessionState(
6901
+ config,
6902
+ 0,
6903
+ // iteration 0 = discovery
6904
+ sessionId,
6905
+ plan,
6906
+ recentProgress
6907
+ );
6908
+ yield* stateStore.write(sessionId, initialState).pipe(
6909
+ Effect17.tapError(
6910
+ (error) => Effect17.logDebug("Failed to write STATE.json, continuing", {
6911
+ error: String(error)
6912
+ })
6913
+ ),
6914
+ Effect17.orElseSucceed(() => void 0)
7070
6915
  );
7071
6916
  }
7072
- const endTimeUtc = yield* DateTime8.now;
7073
- const endTime = DateTime8.toEpochMillis(endTimeUtc);
6917
+ const endTimeUtc = yield* DateTime5.now;
6918
+ const endTime = DateTime5.toEpochMillis(endTimeUtc);
7074
6919
  const events = [...persistEvents];
7075
- const capturedName = yield* Ref10.get(sessionNameRef);
6920
+ const capturedName = yield* Ref5.get(sessionNameRef);
7076
6921
  if (capturedName) {
7077
6922
  if (onSessionName) {
7078
6923
  yield* onSessionName(capturedName).pipe(
7079
- Effect21.tapError(
7080
- (error) => Effect21.logDebug(
6924
+ Effect17.tapError(
6925
+ (error) => Effect17.logDebug(
7081
6926
  "Failed to handle session name, continuing",
7082
6927
  {
7083
6928
  error: String(error),
@@ -7085,7 +6930,7 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
7085
6930
  }
7086
6931
  )
7087
6932
  ),
7088
- Effect21.orElseSucceed(() => void 0)
6933
+ Effect17.orElseSucceed(() => void 0)
7089
6934
  );
7090
6935
  }
7091
6936
  const sessionNameEvent = {
@@ -7104,12 +6949,12 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
7104
6949
  events.push(discoveryCompleted);
7105
6950
  return events;
7106
6951
  })
7107
- ).pipe(Stream7.flatMap((events) => Stream7.fromIterable(events)));
6952
+ ).pipe(Stream6.flatMap((events) => Stream6.fromIterable(events)));
7108
6953
  return pipe(
7109
- Stream7.succeed(discoveryStarted),
7110
- Stream7.concat(Stream7.succeed(analysingToolUse)),
7111
- Stream7.concat(llmStream),
7112
- Stream7.concat(completionStream)
6954
+ Stream6.succeed(discoveryStarted),
6955
+ Stream6.concat(Stream6.succeed(analysingToolUse)),
6956
+ Stream6.concat(llmStream),
6957
+ Stream6.concat(completionStream)
7113
6958
  );
7114
6959
  })
7115
6960
  );
@@ -7117,15 +6962,15 @@ function createDiscoveryStream(llm, signalParser, planStore, currentPlanRef, con
7117
6962
 
7118
6963
  // src/commands/code/orchestrator/iteration.ts
7119
6964
  init_esm_shims();
7120
- import { DateTime as DateTime9, Effect as Effect22, pipe as pipe2, Ref as Ref11, Stream as Stream8 } from "effect";
6965
+ import { DateTime as DateTime6, Effect as Effect18, pipe as pipe2, Ref as Ref6, Stream as Stream7 } from "effect";
7121
6966
  function processTextSignals2(signalParser, text, context) {
7122
- return Effect22.gen(function* () {
6967
+ return Effect18.gen(function* () {
7123
6968
  const events = [];
7124
6969
  let completed = false;
7125
6970
  const parsedSignals = [];
7126
6971
  const signals = yield* signalParser.parse(text).pipe(
7127
- Effect22.tapError(
7128
- (error) => Effect22.logDebug(
6972
+ Effect18.tapError(
6973
+ (error) => Effect18.logDebug(
7129
6974
  "Signal parsing failed, continuing with empty signals",
7130
6975
  {
7131
6976
  error: String(error),
@@ -7133,8 +6978,14 @@ function processTextSignals2(signalParser, text, context) {
7133
6978
  }
7134
6979
  )
7135
6980
  ),
7136
- Effect22.orElseSucceed(() => [])
6981
+ Effect18.orElseSucceed(() => [])
7137
6982
  );
6983
+ if (signals.length > 0) {
6984
+ yield* Effect18.logDebug("Signals parsed", {
6985
+ signals: signals.map((s) => s._tag),
6986
+ count: signals.length
6987
+ });
6988
+ }
7138
6989
  for (const signal of signals) {
7139
6990
  events.push(mapSignalToDomain(signal, context));
7140
6991
  parsedSignals.push(signal);
@@ -7146,7 +6997,7 @@ function processTextSignals2(signalParser, text, context) {
7146
6997
  });
7147
6998
  }
7148
6999
  function processLLMEvent2(signalParser, llmEvent, context) {
7149
- return Effect22.gen(function* () {
7000
+ return Effect18.gen(function* () {
7150
7001
  const domainEvent = mapLLMEventToDomain(llmEvent, context);
7151
7002
  const events = [domainEvent];
7152
7003
  let completed = false;
@@ -7177,11 +7028,11 @@ function processLLMEvent2(signalParser, llmEvent, context) {
7177
7028
  return { events, completed, signals: allSignals };
7178
7029
  });
7179
7030
  }
7180
- function createIterationStream(llm, signalParser, planStore, currentPlanRef, loopCompletedRef, config, iteration, sessionId, worktreePath) {
7181
- return Stream8.unwrap(
7182
- Effect22.gen(function* () {
7183
- const currentPlan = yield* Ref11.get(currentPlanRef);
7184
- const persistenceStateRef = yield* Ref11.make({
7031
+ function createIterationStream(llm, signalParser, planStore, stateStore, progressStore, currentPlanRef, loopCompletedRef, config, iteration, sessionId, worktreePath) {
7032
+ return Stream7.unwrap(
7033
+ Effect18.gen(function* () {
7034
+ const currentPlan = yield* Ref6.get(currentPlanRef);
7035
+ const persistenceStateRef = yield* Ref6.make({
7185
7036
  dirty: false,
7186
7037
  pendingOperation: null
7187
7038
  });
@@ -7189,23 +7040,56 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
7189
7040
  _tag: "IterationStarted",
7190
7041
  iteration
7191
7042
  };
7192
- const llmStream = llm.execute(
7193
- buildPrompt(config, iteration, currentPlan),
7194
- worktreePath ? { cwd: worktreePath } : void 0
7195
- ).pipe(
7196
- Stream8.mapError(
7043
+ const recentEntries = yield* progressStore.getRecent(sessionId, 5).pipe(
7044
+ Effect18.tapError(
7045
+ (error) => Effect18.logDebug("Failed to get recent progress, continuing", {
7046
+ error: String(error)
7047
+ })
7048
+ ),
7049
+ Effect18.orElseSucceed(() => [])
7050
+ );
7051
+ const recentProgress = recentEntries.map(
7052
+ (entry) => `[${entry.action}] Task ${entry.taskId}: ${entry.summary}`
7053
+ );
7054
+ const state = buildSessionState(
7055
+ config,
7056
+ iteration,
7057
+ sessionId,
7058
+ currentPlan,
7059
+ recentProgress
7060
+ );
7061
+ yield* stateStore.write(sessionId, state).pipe(
7062
+ Effect18.tapError(
7063
+ (error) => Effect18.logDebug("Failed to write STATE.json, continuing", {
7064
+ error: String(error)
7065
+ })
7066
+ ),
7067
+ Effect18.orElseSucceed(() => void 0)
7068
+ );
7069
+ const prompt = buildPrompt(config, iteration, currentPlan);
7070
+ const promptPreview = prompt.slice(0, 200);
7071
+ yield* Effect18.logDebug("Building prompt for iteration", {
7072
+ iteration,
7073
+ promptLength: prompt.length,
7074
+ promptPreview: promptPreview.length < prompt.length ? `${promptPreview}...` : promptPreview
7075
+ });
7076
+ const llmStream = llm.execute(prompt, {
7077
+ cwd: worktreePath,
7078
+ yolo: config.yolo
7079
+ }).pipe(
7080
+ Stream7.mapError(
7197
7081
  (e) => new OrchestratorError({
7198
7082
  message: `LLM execution failed: ${String(e)}`,
7199
7083
  phase: "iteration",
7200
7084
  cause: e
7201
7085
  })
7202
7086
  ),
7203
- Stream8.flatMap(
7204
- (llmEvent) => Stream8.unwrap(
7205
- Effect22.gen(function* () {
7206
- const now = yield* DateTime9.now;
7087
+ Stream7.flatMap(
7088
+ (llmEvent) => Stream7.unwrap(
7089
+ Effect18.gen(function* () {
7090
+ const now = yield* DateTime6.now;
7207
7091
  const context = {
7208
- timestamp: DateTime9.toEpochMillis(now)
7092
+ timestamp: DateTime6.toEpochMillis(now)
7209
7093
  };
7210
7094
  const result = yield* processLLMEvent2(
7211
7095
  signalParser,
@@ -7224,14 +7108,14 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
7224
7108
  events.push(...planEvents);
7225
7109
  }
7226
7110
  if (result.completed) {
7227
- yield* Effect22.logInfo(
7111
+ yield* Effect18.logInfo(
7228
7112
  "[DEBUG] createIterationStream: LLM emitted completion signal"
7229
7113
  );
7230
- yield* Ref11.set(loopCompletedRef, true);
7114
+ yield* Ref6.set(loopCompletedRef, true);
7231
7115
  }
7232
- const updatedPlan = yield* Ref11.get(currentPlanRef);
7116
+ const updatedPlan = yield* Ref6.get(currentPlanRef);
7233
7117
  const allComplete = areAllTasksComplete(updatedPlan);
7234
- yield* Effect22.logInfo(
7118
+ yield* Effect18.logInfo(
7235
7119
  "[DEBUG] createIterationStream: Auto-complete check",
7236
7120
  {
7237
7121
  llmEmittedComplete: result.completed,
@@ -7243,18 +7127,18 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
7243
7127
  }
7244
7128
  );
7245
7129
  if (allComplete) {
7246
- yield* Effect22.logInfo(
7130
+ yield* Effect18.logInfo(
7247
7131
  "[DEBUG] createIterationStream: All tasks complete - ending loop"
7248
7132
  );
7249
- yield* Ref11.set(loopCompletedRef, true);
7133
+ yield* Ref6.set(loopCompletedRef, true);
7250
7134
  }
7251
- return Stream8.fromIterable(events);
7135
+ return Stream7.fromIterable(events);
7252
7136
  })
7253
7137
  )
7254
7138
  ),
7255
7139
  // Convert LLM errors to LoopFailed events with iteration context
7256
- Stream8.catchAll(
7257
- (error) => Stream8.succeed({
7140
+ Stream7.catchAll(
7141
+ (error) => Stream7.succeed({
7258
7142
  _tag: "LoopFailed",
7259
7143
  error: {
7260
7144
  message: error.message,
@@ -7264,8 +7148,8 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
7264
7148
  })
7265
7149
  )
7266
7150
  );
7267
- const completionStream = Stream8.fromEffect(
7268
- Effect22.gen(function* () {
7151
+ const completionStream = Stream7.fromEffect(
7152
+ Effect18.gen(function* () {
7269
7153
  const persistEvents = yield* flushPlanPersistence(
7270
7154
  planStore,
7271
7155
  currentPlanRef,
@@ -7277,11 +7161,11 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
7277
7161
  };
7278
7162
  return [...persistEvents, iterCompleted];
7279
7163
  })
7280
- ).pipe(Stream8.flatMap((events) => Stream8.fromIterable(events)));
7164
+ ).pipe(Stream7.flatMap((events) => Stream7.fromIterable(events)));
7281
7165
  return pipe2(
7282
- Stream8.succeed(iterStarted),
7283
- Stream8.concat(llmStream),
7284
- Stream8.concat(completionStream)
7166
+ Stream7.succeed(iterStarted),
7167
+ Stream7.concat(llmStream),
7168
+ Stream7.concat(completionStream)
7285
7169
  );
7286
7170
  })
7287
7171
  );
@@ -7289,15 +7173,18 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
7289
7173
 
7290
7174
  // src/commands/code/orchestrator/loop.ts
7291
7175
  function runLoop(config) {
7292
- return Stream9.unwrap(
7293
- Effect23.gen(function* () {
7176
+ return Stream8.unwrap(
7177
+ Effect19.gen(function* () {
7294
7178
  const llm = yield* LLM;
7295
7179
  const signalParser = yield* SignalParser;
7296
7180
  const sessionStore = yield* SessionStore;
7297
7181
  const planStore = yield* PlanStore;
7182
+ const progressStore = yield* ProgressStore;
7298
7183
  const git = yield* Git;
7299
- const session = yield* sessionStore.create(config.task).pipe(
7300
- Effect23.mapError(
7184
+ const stateStore = yield* StateStore;
7185
+ const promptStore = yield* PromptStore;
7186
+ const session = yield* sessionStore.create(config.task, config.sessionId).pipe(
7187
+ Effect19.mapError(
7301
7188
  (e) => new OrchestratorError({
7302
7189
  message: `Failed to create session: ${e.message}`,
7303
7190
  phase: "setup",
@@ -7306,15 +7193,15 @@ function runLoop(config) {
7306
7193
  )
7307
7194
  );
7308
7195
  const baseBranch = yield* git.getCurrentBranch().pipe(
7309
- Effect23.tapError(
7310
- (error) => Effect23.logDebug("Failed to get current branch", {
7196
+ Effect19.tapError(
7197
+ (error) => Effect19.logDebug("Failed to get current branch", {
7311
7198
  error: String(error)
7312
7199
  })
7313
7200
  ),
7314
- Effect23.orElseSucceed(() => void 0)
7201
+ Effect19.orElseSucceed(() => void 0)
7315
7202
  );
7316
7203
  const worktreePath = yield* git.createWorktree(session.id).pipe(
7317
- Effect23.mapError(
7204
+ Effect19.mapError(
7318
7205
  (e) => new OrchestratorError({
7319
7206
  message: `Failed to create worktree: ${e.message}`,
7320
7207
  phase: "setup",
@@ -7329,15 +7216,15 @@ function runLoop(config) {
7329
7216
  branchName,
7330
7217
  baseBranch
7331
7218
  }).pipe(
7332
- Effect23.tapError(
7333
- (error) => Effect23.logDebug("Failed to update session with worktree info", {
7219
+ Effect19.tapError(
7220
+ (error) => Effect19.logDebug("Failed to update session with worktree info", {
7334
7221
  error: String(error)
7335
7222
  })
7336
7223
  ),
7337
- Effect23.orElseSucceed(() => void 0)
7224
+ Effect19.orElseSucceed(() => void 0)
7338
7225
  );
7339
- const startTimeUtc = yield* DateTime10.now;
7340
- const startTime = DateTime10.toEpochMillis(startTimeUtc);
7226
+ const startTimeUtc = yield* DateTime7.now;
7227
+ const startTime = DateTime7.toEpochMillis(startTimeUtc);
7341
7228
  const worktreeCreated = {
7342
7229
  _tag: "WorktreeCreated",
7343
7230
  sessionId: session.id,
@@ -7345,18 +7232,18 @@ function runLoop(config) {
7345
7232
  branchName,
7346
7233
  timestamp: startTime
7347
7234
  };
7348
- const loopCompletedRef = yield* Ref12.make(false);
7349
- const currentPlanRef = yield* Ref12.make(void 0);
7235
+ const loopCompletedRef = yield* Ref7.make(false);
7236
+ const currentPlanRef = yield* Ref7.make(void 0);
7350
7237
  const initialSession = { ...session, baseBranch };
7351
- const sessionRef = yield* Ref12.make(initialSession);
7238
+ const sessionRef = yield* Ref7.make(initialSession);
7352
7239
  const maxIterations = config.maxIterations === 0 ? Number.POSITIVE_INFINITY : config.maxIterations;
7353
7240
  const loopStarted = {
7354
7241
  _tag: "LoopStarted",
7355
7242
  config,
7356
7243
  timestamp: startTime
7357
7244
  };
7358
- const handleSessionName = (displayName) => Effect23.gen(function* () {
7359
- const currentSession = yield* Ref12.get(sessionRef);
7245
+ const handleSessionName = (displayName) => Effect19.gen(function* () {
7246
+ const currentSession = yield* Ref7.get(sessionRef);
7360
7247
  const newBranchName = yield* git.renameBranch(
7361
7248
  session.id,
7362
7249
  displayName
@@ -7367,33 +7254,38 @@ function runLoop(config) {
7367
7254
  branchName: newBranchName
7368
7255
  };
7369
7256
  yield* sessionStore.update(session.id, updatedSession);
7370
- yield* Ref12.set(sessionRef, updatedSession);
7257
+ yield* Ref7.set(sessionRef, updatedSession);
7371
7258
  });
7372
7259
  const discoveryStream = createDiscoveryStream(
7373
7260
  llm,
7374
7261
  signalParser,
7375
7262
  planStore,
7263
+ stateStore,
7264
+ promptStore,
7265
+ progressStore,
7376
7266
  currentPlanRef,
7377
7267
  config,
7378
7268
  session.id,
7379
7269
  worktreePath,
7380
7270
  handleSessionName
7381
7271
  );
7382
- const iterationsStream = Stream9.unfoldEffect(
7272
+ const iterationsStream = Stream8.unfoldEffect(
7383
7273
  1,
7384
- (iteration) => Effect23.gen(function* () {
7385
- const completed = yield* Ref12.get(loopCompletedRef);
7274
+ (iteration) => Effect19.gen(function* () {
7275
+ const completed = yield* Ref7.get(loopCompletedRef);
7386
7276
  if (completed || iteration > maxIterations) {
7387
7277
  return Option.none();
7388
7278
  }
7389
7279
  return Option.some([iteration, iteration + 1]);
7390
7280
  })
7391
7281
  ).pipe(
7392
- Stream9.flatMap(
7282
+ Stream8.flatMap(
7393
7283
  (iteration) => createIterationStream(
7394
7284
  llm,
7395
7285
  signalParser,
7396
7286
  planStore,
7287
+ stateStore,
7288
+ progressStore,
7397
7289
  currentPlanRef,
7398
7290
  loopCompletedRef,
7399
7291
  config,
@@ -7419,17 +7311,17 @@ function runLoop(config) {
7419
7311
  worktreePath
7420
7312
  );
7421
7313
  return pipe3(
7422
- Stream9.succeed(loopStarted),
7423
- Stream9.concat(Stream9.succeed(worktreeCreated)),
7424
- Stream9.concat(discoveryStream),
7425
- Stream9.concat(iterationsStream),
7426
- Stream9.concat(completionStream)
7314
+ Stream8.succeed(loopStarted),
7315
+ Stream8.concat(Stream8.succeed(worktreeCreated)),
7316
+ Stream8.concat(discoveryStream),
7317
+ Stream8.concat(iterationsStream),
7318
+ Stream8.concat(completionStream)
7427
7319
  );
7428
7320
  }).pipe(
7429
7321
  // Also catch setup errors (e.g., session creation failure)
7430
- Effect23.catchAll(
7431
- (error) => Effect23.succeed(
7432
- Stream9.succeed({
7322
+ Effect19.catchAll(
7323
+ (error) => Effect19.succeed(
7324
+ Stream8.succeed({
7433
7325
  _tag: "LoopFailed",
7434
7326
  error: {
7435
7327
  message: error.message,
@@ -7453,33 +7345,33 @@ ${completedTasks}
7453
7345
  Generated by Ferix`;
7454
7346
  }
7455
7347
  function createCompletionStream(sessionStore, git, sessionRef, config, startTime, loopCompletedRef, _worktreePath) {
7456
- return Stream9.unwrap(
7457
- Effect23.gen(function* () {
7458
- const session = yield* Ref12.get(sessionRef);
7459
- const endTimeUtc = yield* DateTime10.now;
7460
- const endTime = DateTime10.toEpochMillis(endTimeUtc);
7348
+ return Stream8.unwrap(
7349
+ Effect19.gen(function* () {
7350
+ const session = yield* Ref7.get(sessionRef);
7351
+ const endTimeUtc = yield* DateTime7.now;
7352
+ const endTime = DateTime7.toEpochMillis(endTimeUtc);
7461
7353
  const durationMs = endTime - startTime;
7462
- const completed = yield* Ref12.get(loopCompletedRef);
7354
+ const completed = yield* Ref7.get(loopCompletedRef);
7463
7355
  yield* git.commitChanges(session.id, `feat: complete session ${session.id}`).pipe(
7464
- Effect23.tapError(
7465
- (error) => Effect23.logDebug("Final commit failed, continuing", {
7356
+ Effect19.tapError(
7357
+ (error) => Effect19.logDebug("Final commit failed, continuing", {
7466
7358
  sessionId: session.id,
7467
7359
  error: String(error)
7468
7360
  })
7469
7361
  ),
7470
- Effect23.orElseSucceed(() => void 0)
7362
+ Effect19.orElseSucceed(() => void 0)
7471
7363
  );
7472
7364
  let branchPushed = false;
7473
7365
  if (config.push === true) {
7474
7366
  const pushResult = yield* git.pushBranch(session.id).pipe(
7475
- Effect23.map(() => true),
7476
- Effect23.tapError(
7477
- (error) => Effect23.logDebug("Push failed, continuing", {
7367
+ Effect19.map(() => true),
7368
+ Effect19.tapError(
7369
+ (error) => Effect19.logDebug("Push failed, continuing", {
7478
7370
  sessionId: session.id,
7479
7371
  error: String(error)
7480
7372
  })
7481
7373
  ),
7482
- Effect23.orElseSucceed(() => false)
7374
+ Effect19.orElseSucceed(() => false)
7483
7375
  );
7484
7376
  branchPushed = pushResult;
7485
7377
  }
@@ -7488,25 +7380,25 @@ function createCompletionStream(sessionStore, git, sessionRef, config, startTime
7488
7380
  const title = `feat: ${session.originalTask.slice(0, 50)}`;
7489
7381
  const body = buildPRBody(session, config);
7490
7382
  const prResult = yield* git.createPR(session.id, title, body, session.baseBranch).pipe(
7491
- Effect23.map((url) => url),
7492
- Effect23.tapError(
7493
- (error) => Effect23.logDebug("PR creation failed, continuing", {
7383
+ Effect19.map((url) => url),
7384
+ Effect19.tapError(
7385
+ (error) => Effect19.logDebug("PR creation failed, continuing", {
7494
7386
  sessionId: session.id,
7495
7387
  error: String(error)
7496
7388
  })
7497
7389
  ),
7498
- Effect23.orElseSucceed(() => void 0)
7390
+ Effect19.orElseSucceed(() => void 0)
7499
7391
  );
7500
7392
  prUrl = prResult;
7501
7393
  }
7502
7394
  yield* git.removeWorktreeKeepBranch(session.id).pipe(
7503
- Effect23.tapError(
7504
- (error) => Effect23.logDebug("Worktree cleanup failed, continuing", {
7395
+ Effect19.tapError(
7396
+ (error) => Effect19.logDebug("Worktree cleanup failed, continuing", {
7505
7397
  sessionId: session.id,
7506
7398
  error: String(error)
7507
7399
  })
7508
7400
  ),
7509
- Effect23.orElseSucceed(() => void 0)
7401
+ Effect19.orElseSucceed(() => void 0)
7510
7402
  );
7511
7403
  const worktreeRemoved = {
7512
7404
  _tag: "WorktreeRemoved",
@@ -7527,13 +7419,13 @@ function createCompletionStream(sessionStore, git, sessionRef, config, startTime
7527
7419
  status: completed ? "completed" : "paused",
7528
7420
  worktreePath: void 0
7529
7421
  }).pipe(
7530
- Effect23.tapError(
7531
- (error) => Effect23.logDebug("Session update failed, continuing", {
7422
+ Effect19.tapError(
7423
+ (error) => Effect19.logDebug("Session update failed, continuing", {
7532
7424
  sessionId: session.id,
7533
7425
  error: String(error)
7534
7426
  })
7535
7427
  ),
7536
- Effect23.orElseSucceed(() => void 0)
7428
+ Effect19.orElseSucceed(() => void 0)
7537
7429
  );
7538
7430
  const events = [worktreeRemoved];
7539
7431
  if (branchPushed) {
@@ -7554,27 +7446,35 @@ function createCompletionStream(sessionStore, git, sessionRef, config, startTime
7554
7446
  });
7555
7447
  }
7556
7448
  events.push({ _tag: "LoopCompleted", summary });
7557
- return Stream9.fromIterable(events);
7449
+ return Stream8.fromIterable(events);
7558
7450
  })
7559
7451
  );
7560
7452
  }
7561
7453
 
7562
7454
  // src/commands/code/action.ts
7455
+ function generateSessionId2() {
7456
+ const id = humanId2({ separator: "-", capitalize: false });
7457
+ return `${id}-${Date.now()}`;
7458
+ }
7563
7459
  function run(options) {
7564
7460
  const { config, consumer: consumerType = "headless", onEvent } = options;
7565
- const events = runLoop(config);
7566
- const eventsWithCallback = onEvent ? events.pipe(Stream10.tap((event) => Effect24.sync(() => onEvent(event)))) : events;
7567
- const layers = config.provider ? createProductionLayers(config.provider) : ProductionLayers;
7568
- const eventsWithLayers = eventsWithCallback.pipe(Stream10.provideLayer(layers));
7461
+ const sessionId = config.sessionId ?? generateSessionId2();
7462
+ const configWithSession = { ...config, sessionId };
7463
+ const events = runLoop(configWithSession);
7464
+ const eventsWithCallback = onEvent ? events.pipe(Stream9.tap((event) => Effect20.sync(() => onEvent(event)))) : events;
7465
+ const baseLayers = config.provider ? createProductionLayers(config.provider) : ProductionLayers;
7466
+ const loggerLayer = createLoggerLayer(config.debug ?? false, sessionId);
7467
+ const layers = Layer12.merge(baseLayers, loggerLayer);
7468
+ const eventsWithLayers = eventsWithCallback.pipe(Stream9.provideLayer(layers));
7569
7469
  if (consumerType === "none") {
7570
- return eventsWithLayers.pipe(Stream10.runDrain);
7470
+ return eventsWithLayers.pipe(Stream9.runDrain);
7571
7471
  }
7572
7472
  const consumer = consumerType === "tui" ? createTUIConsumer() : createHeadlessConsumer();
7573
7473
  return consumer.consume(eventsWithLayers);
7574
7474
  }
7575
7475
  function main(config) {
7576
7476
  const consumerType = process.stdout.isTTY ? "tui" : "headless";
7577
- return run({ config, consumer: consumerType }).pipe(Effect24.runPromise);
7477
+ return run({ config, consumer: consumerType }).pipe(Effect20.runPromise);
7578
7478
  }
7579
7479
 
7580
7480
  // src/commands/code/services/index.ts
@@ -7586,7 +7486,10 @@ var registerCodeCommand = (program2) => {
7586
7486
  "--provider <name>",
7587
7487
  "LLM provider to use (claude, cursor, opencode)",
7588
7488
  "claude"
7589
- ).action(async (task, options) => {
7489
+ ).option(
7490
+ "--no-yolo",
7491
+ "Require permission prompts (default runs in yolo mode on isolated worktree)"
7492
+ ).option("-d, --debug", "Enable debug logging to .ferix/logs/<session>.log").action(async (task, options) => {
7590
7493
  const config = {
7591
7494
  task,
7592
7495
  maxIterations: Number.parseInt(options.iterations, 10),
@@ -7594,7 +7497,9 @@ var registerCodeCommand = (program2) => {
7594
7497
  branch: options.branch,
7595
7498
  push: options.push,
7596
7499
  pr: options.pr,
7597
- provider: options.provider
7500
+ provider: options.provider,
7501
+ yolo: options.yolo ?? true,
7502
+ debug: options.debug
7598
7503
  };
7599
7504
  try {
7600
7505
  await main(config);
@@ -7652,16 +7557,16 @@ var createSpinner = (text) => {
7652
7557
  // src/commands/sync/action.ts
7653
7558
  init_esm_shims();
7654
7559
  import { access as access5 } from "fs/promises";
7655
- import { dirname as dirname3, resolve } from "path";
7560
+ import { dirname as dirname4, resolve } from "path";
7656
7561
  import { cancel } from "@clack/prompts";
7657
- import { Effect as Effect29 } from "effect";
7562
+ import { Effect as Effect25 } from "effect";
7658
7563
  import pc19 from "picocolors";
7659
7564
 
7660
7565
  // src/commands/sync/detect-agents.ts
7661
7566
  init_esm_shims();
7662
7567
  import { access as access3 } from "fs/promises";
7663
- import { join as join7 } from "path";
7664
- import { Effect as Effect25 } from "effect";
7568
+ import { join as join10 } from "path";
7569
+ import { Effect as Effect21 } from "effect";
7665
7570
  var AGENT_DIRECTORIES = {
7666
7571
  opencode: [".opencode"],
7667
7572
  "claude-code": [".claude"],
@@ -7674,7 +7579,7 @@ var AGENT_DIRECTORIES = {
7674
7579
  var SUPPORTED_AGENTS = Object.keys(
7675
7580
  AGENT_DIRECTORIES
7676
7581
  );
7677
- var directoryExists2 = (dirPath) => Effect25.promise(async () => {
7582
+ var directoryExists2 = (dirPath) => Effect21.promise(async () => {
7678
7583
  try {
7679
7584
  await access3(dirPath);
7680
7585
  return true;
@@ -7684,18 +7589,18 @@ var directoryExists2 = (dirPath) => Effect25.promise(async () => {
7684
7589
  });
7685
7590
  var isAgentPresent = (projectDir, agent) => {
7686
7591
  const directories = AGENT_DIRECTORIES[agent];
7687
- return Effect25.forEach(
7592
+ return Effect21.forEach(
7688
7593
  directories,
7689
- (dir) => directoryExists2(join7(projectDir, dir))
7690
- ).pipe(Effect25.map((results) => results.some((exists) => exists)));
7594
+ (dir) => directoryExists2(join10(projectDir, dir))
7595
+ ).pipe(Effect21.map((results) => results.some((exists) => exists)));
7691
7596
  };
7692
- var detectAgents = (projectDir) => Effect25.forEach(
7597
+ var detectAgents = (projectDir) => Effect21.forEach(
7693
7598
  SUPPORTED_AGENTS,
7694
7599
  (agent) => isAgentPresent(projectDir, agent).pipe(
7695
- Effect25.map((present) => present ? agent : null)
7600
+ Effect21.map((present) => present ? agent : null)
7696
7601
  )
7697
7602
  ).pipe(
7698
- Effect25.map(
7603
+ Effect21.map(
7699
7604
  (results) => results.filter((agent) => agent !== null)
7700
7605
  )
7701
7606
  );
@@ -7713,28 +7618,24 @@ var components = componentsGeneric();
7713
7618
 
7714
7619
  // src/commands/sync/find-skills.ts
7715
7620
  import { ConvexHttpClient } from "convex/browser";
7716
- import { Effect as Effect26, Schema as S24 } from "effect";
7621
+ import { Effect as Effect22, Schema as S23 } from "effect";
7717
7622
 
7718
7623
  // src/commands/sync/errors.ts
7719
7624
  init_esm_shims();
7720
7625
  import { Data as Data2 } from "effect";
7721
- var PackageJsonError = class extends Data2.TaggedError("PackageJsonError") {
7722
- };
7723
7626
  var SchemaValidationError = class extends Data2.TaggedError(
7724
7627
  "SchemaValidationError"
7725
7628
  ) {
7726
7629
  };
7727
7630
  var ConvexError = class extends Data2.TaggedError("ConvexError") {
7728
7631
  };
7729
- var NpmResolveError = class extends Data2.TaggedError("NpmResolveError") {
7730
- };
7731
7632
  var SkillInstallError = class extends Data2.TaggedError("SkillInstallError") {
7732
7633
  };
7733
7634
 
7734
7635
  // src/commands/sync/types.ts
7735
7636
  init_esm_shims();
7736
- import { Schema as S23 } from "effect";
7737
- var AgentNameSchema = S23.Literal(
7637
+ import { Schema as S22 } from "effect";
7638
+ var AgentNameSchema = S22.Literal(
7738
7639
  "opencode",
7739
7640
  "claude-code",
7740
7641
  "cursor",
@@ -7743,73 +7644,22 @@ var AgentNameSchema = S23.Literal(
7743
7644
  "openhands",
7744
7645
  "windsurf"
7745
7646
  );
7746
- var PackageNameSchema = S23.String.pipe(
7747
- S23.pattern(/^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/),
7748
- S23.brand("PackageName")
7749
- );
7750
- var GitHubOwnerSchema = S23.String.pipe(
7751
- S23.pattern(/^[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/),
7752
- S23.brand("GitHubOwner")
7753
- );
7754
- var GitHubRepoSchema = S23.String.pipe(
7755
- S23.pattern(/^[a-zA-Z0-9._-]+$/),
7756
- S23.brand("GitHubRepo")
7757
- );
7758
- var GitHubUrlSchema = S23.String.pipe(
7759
- S23.pattern(/^https:\/\/github\.com\/[^/]+\/[^/]+$/),
7760
- S23.brand("GitHubUrl")
7761
- );
7762
- var SkillRepoSchema = S23.Struct({
7763
- owner: S23.String,
7764
- repo: S23.String,
7765
- githubUrl: S23.String
7766
- });
7767
- var PackageOrgSchema = S23.Struct({
7768
- packageName: S23.String,
7769
- githubOrg: S23.NullOr(S23.String)
7770
- });
7771
- var PackageOrgsResponseSchema = S23.Array(PackageOrgSchema);
7772
- var SkillReposResponseSchema = S23.Array(SkillRepoSchema);
7773
- var DependencyVersionSchema = S23.String;
7774
- var DependenciesSchema = S23.Record({
7775
- key: S23.String,
7776
- value: DependencyVersionSchema
7777
- });
7778
- var WorkspacesSchema = S23.Union(
7779
- S23.Array(S23.String),
7780
- S23.Struct({ packages: S23.Array(S23.String) })
7781
- );
7782
- var PackageJsonSchema = S23.Struct({
7783
- name: S23.optional(S23.String),
7784
- version: S23.optional(S23.String),
7785
- dependencies: S23.optional(DependenciesSchema),
7786
- devDependencies: S23.optional(DependenciesSchema),
7787
- workspaces: S23.optional(WorkspacesSchema)
7788
- });
7789
- var SyncOptionsSchema = S23.Struct({
7790
- dryRun: S23.optional(S23.Boolean),
7791
- global: S23.optional(S23.Boolean),
7792
- dev: S23.optional(S23.Boolean)
7793
- });
7794
- var InstallOptionsSchema = S23.Struct({
7795
- dryRun: S23.optional(S23.Boolean),
7796
- global: S23.optional(S23.Boolean),
7797
- agents: S23.optional(S23.Array(AgentNameSchema))
7798
- });
7799
- var SyncResultSchema = S23.Struct({
7800
- dependencies: S23.Array(S23.String),
7801
- orgs: S23.Array(S23.String),
7802
- skillRepos: S23.Array(SkillRepoSchema),
7803
- installed: S23.Array(S23.String),
7804
- packageJsonCount: S23.Number
7805
- });
7806
- var decodePackageJson = S23.decodeUnknown(PackageJsonSchema);
7807
- var decodePackageOrgsResponse = S23.decodeUnknown(
7808
- PackageOrgsResponseSchema
7809
- );
7810
- var decodeSkillReposResponse = S23.decodeUnknown(
7811
- SkillReposResponseSchema
7812
- );
7647
+ var SkillRepoSchema = S22.Struct({
7648
+ owner: S22.String,
7649
+ repo: S22.String,
7650
+ githubUrl: S22.String
7651
+ });
7652
+ var PackageOrgSchema = S22.Struct({
7653
+ packageName: S22.String,
7654
+ githubOrg: S22.NullOr(S22.String)
7655
+ });
7656
+ var PackageOrgsResponseSchema = S22.Array(PackageOrgSchema);
7657
+ var SkillReposResponseSchema = S22.Array(SkillRepoSchema);
7658
+ var InstallOptionsSchema = S22.Struct({
7659
+ dryRun: S22.optional(S22.Boolean),
7660
+ global: S22.optional(S22.Boolean),
7661
+ agents: S22.optional(S22.Array(AgentNameSchema))
7662
+ });
7813
7663
  var CONVEX_URL_PROD = "https://groovy-mallard-649.convex.cloud";
7814
7664
  var CONVEX_URL_DEV = "https://majestic-gnu-964.convex.cloud";
7815
7665
  var getConvexUrl = (dev) => dev ? CONVEX_URL_DEV : CONVEX_URL_PROD;
@@ -7821,8 +7671,8 @@ var NON_NPM_VERSION_PREFIXES = [
7821
7671
  ];
7822
7672
 
7823
7673
  // src/commands/sync/find-skills.ts
7824
- var findSkillRepos = (orgs, dev) => Effect26.gen(function* () {
7825
- const response = yield* Effect26.tryPromise({
7674
+ var findSkillRepos = (orgs, dev) => Effect22.gen(function* () {
7675
+ const response = yield* Effect22.tryPromise({
7826
7676
  try: async () => {
7827
7677
  const client = new ConvexHttpClient(getConvexUrl(dev));
7828
7678
  return await client.query(api.directories.getByOwners, {
@@ -7835,10 +7685,10 @@ var findSkillRepos = (orgs, dev) => Effect26.gen(function* () {
7835
7685
  cause: error
7836
7686
  })
7837
7687
  });
7838
- const validated = yield* S24.decodeUnknown(SkillReposResponseSchema)(
7688
+ const validated = yield* S23.decodeUnknown(SkillReposResponseSchema)(
7839
7689
  response
7840
7690
  ).pipe(
7841
- Effect26.mapError(
7691
+ Effect22.mapError(
7842
7692
  (error) => new SchemaValidationError({
7843
7693
  message: "Invalid response from directories.getByOwners",
7844
7694
  context: "findSkillRepos",
@@ -7851,8 +7701,8 @@ var findSkillRepos = (orgs, dev) => Effect26.gen(function* () {
7851
7701
 
7852
7702
  // src/commands/sync/helpers.ts
7853
7703
  init_esm_shims();
7854
- import { access as access4, readdir as readdir2, readFile as readFile7 } from "fs/promises";
7855
- import { dirname as dirname2, join as join8 } from "path";
7704
+ import { access as access4, readdir as readdir2, readFile as readFile8 } from "fs/promises";
7705
+ import { dirname as dirname3, join as join11 } from "path";
7856
7706
  var isNonNpmDependency = (version) => NON_NPM_VERSION_PREFIXES.some((prefix) => version.startsWith(prefix));
7857
7707
  var extractDependencies = (pkg) => {
7858
7708
  const deps = pkg.dependencies ?? {};
@@ -7890,15 +7740,15 @@ var GLOB_SUFFIX_PATTERN = /\/\*+$/;
7890
7740
  var expandGlobPattern = async (rootDir, pattern) => {
7891
7741
  if (pattern.endsWith("/*") || pattern.endsWith("/**")) {
7892
7742
  const baseDir = pattern.replace(GLOB_SUFFIX_PATTERN, "");
7893
- const fullPath2 = join8(rootDir, baseDir);
7743
+ const fullPath2 = join11(rootDir, baseDir);
7894
7744
  try {
7895
7745
  const entries = await readdir2(fullPath2, { withFileTypes: true });
7896
- return entries.filter((entry) => entry.isDirectory()).map((entry) => join8(fullPath2, entry.name));
7746
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => join11(fullPath2, entry.name));
7897
7747
  } catch {
7898
7748
  return [];
7899
7749
  }
7900
7750
  }
7901
- const fullPath = join8(rootDir, pattern);
7751
+ const fullPath = join11(rootDir, pattern);
7902
7752
  try {
7903
7753
  await access4(fullPath);
7904
7754
  return [fullPath];
@@ -7907,11 +7757,11 @@ var expandGlobPattern = async (rootDir, pattern) => {
7907
7757
  }
7908
7758
  };
7909
7759
  var readPackageJsonFile = async (filePath) => {
7910
- const content = await readFile7(filePath, "utf-8");
7760
+ const content = await readFile8(filePath, "utf-8");
7911
7761
  return JSON.parse(content);
7912
7762
  };
7913
7763
  var discoverPackageJsonFiles = async (rootPath, rootPkg) => {
7914
- const rootDir = dirname2(rootPath);
7764
+ const rootDir = dirname3(rootPath);
7915
7765
  const patterns = extractWorkspacePatterns(rootPkg);
7916
7766
  if (patterns.length === 0) {
7917
7767
  return [rootPath];
@@ -7920,7 +7770,7 @@ var discoverPackageJsonFiles = async (rootPath, rootPkg) => {
7920
7770
  for (const pattern of patterns) {
7921
7771
  const dirs = await expandGlobPattern(rootDir, pattern);
7922
7772
  for (const dir of dirs) {
7923
- const pkgPath = join8(dir, "package.json");
7773
+ const pkgPath = join11(dir, "package.json");
7924
7774
  try {
7925
7775
  await access4(pkgPath);
7926
7776
  packageJsonPaths.push(pkgPath);
@@ -7935,9 +7785,9 @@ var discoverPackageJsonFiles = async (rootPath, rootPkg) => {
7935
7785
  init_esm_shims();
7936
7786
  import { exec as exec2 } from "child_process";
7937
7787
  import { promisify as promisify2 } from "util";
7938
- import { Effect as Effect27 } from "effect";
7788
+ import { Effect as Effect23 } from "effect";
7939
7789
  var execAsync2 = promisify2(exec2);
7940
- var installSingleSkill = (repo, options) => Effect27.tryPromise({
7790
+ var installSingleSkill = (repo, options) => Effect23.tryPromise({
7941
7791
  try: async () => {
7942
7792
  const repoId = `${repo.owner}/${repo.repo}`;
7943
7793
  const globalFlag = options.global === true ? " --global" : "";
@@ -7957,9 +7807,9 @@ var installSingleSkill = (repo, options) => Effect27.tryPromise({
7957
7807
  });
7958
7808
  var installSkills = (repos, options = {}) => {
7959
7809
  if (options.dryRun === true) {
7960
- return Effect27.succeed(repos.map((r) => `${r.owner}/${r.repo}`));
7810
+ return Effect23.succeed(repos.map((r) => `${r.owner}/${r.repo}`));
7961
7811
  }
7962
- return Effect27.forEach(repos, (repo) => installSingleSkill(repo, options), {
7812
+ return Effect23.forEach(repos, (repo) => installSingleSkill(repo, options), {
7963
7813
  concurrency: 1
7964
7814
  });
7965
7815
  };
@@ -7967,9 +7817,9 @@ var installSkills = (repos, options = {}) => {
7967
7817
  // src/commands/sync/resolve-orgs.ts
7968
7818
  init_esm_shims();
7969
7819
  import { ConvexHttpClient as ConvexHttpClient2 } from "convex/browser";
7970
- import { Effect as Effect28, Schema as S25 } from "effect";
7971
- var resolvePackageOrgs = (packageNames, dev) => Effect28.gen(function* () {
7972
- const response = yield* Effect28.tryPromise({
7820
+ import { Effect as Effect24, Schema as S24 } from "effect";
7821
+ var resolvePackageOrgs = (packageNames, dev) => Effect24.gen(function* () {
7822
+ const response = yield* Effect24.tryPromise({
7973
7823
  try: async () => {
7974
7824
  const client = new ConvexHttpClient2(getConvexUrl(dev));
7975
7825
  return await client.action(api.packageOrg.resolve, {
@@ -7982,10 +7832,10 @@ var resolvePackageOrgs = (packageNames, dev) => Effect28.gen(function* () {
7982
7832
  cause: error
7983
7833
  })
7984
7834
  });
7985
- const validated = yield* S25.decodeUnknown(PackageOrgsResponseSchema)(
7835
+ const validated = yield* S24.decodeUnknown(PackageOrgsResponseSchema)(
7986
7836
  response
7987
7837
  ).pipe(
7988
- Effect28.mapError(
7838
+ Effect24.mapError(
7989
7839
  (error) => new SchemaValidationError({
7990
7840
  message: "Invalid response from packageOrg.resolve",
7991
7841
  context: "resolvePackageOrgs",
@@ -8150,7 +8000,7 @@ var extractAllDependencies = async (state) => {
8150
8000
  var resolveOrganizations = async (state, isDev) => {
8151
8001
  state.spinner = createSpinner("Resolving GitHub organizations...").start();
8152
8002
  try {
8153
- const packageOrgs = await Effect29.runPromise(
8003
+ const packageOrgs = await Effect25.runPromise(
8154
8004
  resolvePackageOrgs(state.dependencies, isDev)
8155
8005
  );
8156
8006
  state.orgs = Array.from(
@@ -8175,7 +8025,7 @@ var resolveOrganizations = async (state, isDev) => {
8175
8025
  var findRepositories = async (state, isDev) => {
8176
8026
  state.spinner = createSpinner("Searching for skill repositories...").start();
8177
8027
  try {
8178
- state.skillRepos = await Effect29.runPromise(
8028
+ state.skillRepos = await Effect25.runPromise(
8179
8029
  findSkillRepos(state.orgs, isDev)
8180
8030
  );
8181
8031
  if (state.skillRepos.length === 0) {
@@ -8197,7 +8047,7 @@ var findRepositories = async (state, isDev) => {
8197
8047
  var detectProjectAgents = async (state, projectDir) => {
8198
8048
  state.spinner = createSpinner("Detecting coding agents...").start();
8199
8049
  try {
8200
- state.detectedAgents = await Effect29.runPromise(detectAgents(projectDir));
8050
+ state.detectedAgents = await Effect25.runPromise(detectAgents(projectDir));
8201
8051
  if (state.detectedAgents.length === 0) {
8202
8052
  state.spinner.info("No coding agents detected");
8203
8053
  } else {
@@ -8224,7 +8074,7 @@ var determineAgents = async (state, packagePath, manualAgents, skipSelection) =>
8224
8074
  printSuccess(`Using specified agents: ${pc19.cyan(manualAgents.join(", "))}`);
8225
8075
  return manualAgents;
8226
8076
  }
8227
- const projectDir = dirname3(resolve(packagePath));
8077
+ const projectDir = dirname4(resolve(packagePath));
8228
8078
  await detectProjectAgents(state, projectDir);
8229
8079
  if (skipSelection) {
8230
8080
  if (state.detectedAgents.length === 0) {
@@ -8284,7 +8134,7 @@ var installRepositories = async (state, reposToInstall, isGlobal, agents) => {
8284
8134
  `Installing ${pc19.cyan(repo.owner)}${pc19.dim("/")}${pc19.white(repo.repo)}...`
8285
8135
  ).start();
8286
8136
  try {
8287
- await Effect29.runPromise(
8137
+ await Effect25.runPromise(
8288
8138
  installSkills([repo], {
8289
8139
  dryRun: false,
8290
8140
  global: isGlobal,