ferix-code 0.0.2-beta.18 → 0.0.2-beta.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -96,14 +96,58 @@ declare const GitError_base: new <A extends Record<string, any> = {}>(args: effe
96
96
  */
97
97
  declare class GitError extends GitError_base<{
98
98
  readonly message: string;
99
- readonly operation: "createWorktree" | "removeWorktree" | "removeWorktreeKeepBranch" | "commit" | "push" | "createPR" | "renameBranch" | "status";
99
+ readonly operation: "createWorktree" | "removeWorktree" | "removeWorktreeKeepBranch" | "commit" | "push" | "createPR" | "renameBranch" | "branchLookup" | "getCurrentBranch" | "status";
100
+ readonly cause?: unknown;
101
+ }> {
102
+ }
103
+ declare const TokenBudgetError_base: new <A extends Record<string, any> = {}>(args: effect_Types.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => effect_Cause.YieldableError & {
104
+ readonly _tag: "TokenBudgetError";
105
+ } & Readonly<A>;
106
+ /**
107
+ * Error that occurs when token budget is exceeded.
108
+ */
109
+ declare class TokenBudgetError extends TokenBudgetError_base<{
110
+ readonly message: string;
111
+ /** Total tokens used */
112
+ readonly budgetUsed: number;
113
+ /** Maximum tokens available */
114
+ readonly budgetMax: number;
115
+ /** Sections that couldn't fit */
116
+ readonly overflowSections: readonly string[];
117
+ }> {
118
+ }
119
+ declare const RetryExhaustedError_base: new <A extends Record<string, any> = {}>(args: effect_Types.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => effect_Cause.YieldableError & {
120
+ readonly _tag: "RetryExhaustedError";
121
+ } & Readonly<A>;
122
+ /**
123
+ * Error that occurs when all retry attempts are exhausted.
124
+ */
125
+ declare class RetryExhaustedError extends RetryExhaustedError_base<{
126
+ readonly message: string;
127
+ /** Number of attempts made */
128
+ readonly attempts: number;
129
+ /** The final error that caused failure */
130
+ readonly finalError: string;
131
+ /** Iteration where retries were exhausted */
132
+ readonly iteration: number;
133
+ }> {
134
+ }
135
+ declare const MetricsError_base: new <A extends Record<string, any> = {}>(args: effect_Types.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => effect_Cause.YieldableError & {
136
+ readonly _tag: "MetricsError";
137
+ } & Readonly<A>;
138
+ /**
139
+ * Error that occurs during metrics operations.
140
+ */
141
+ declare class MetricsError extends MetricsError_base<{
142
+ readonly message: string;
143
+ readonly operation: "record" | "get" | "clear";
100
144
  readonly cause?: unknown;
101
145
  }> {
102
146
  }
103
147
  /**
104
148
  * Union of all possible errors in the system.
105
149
  */
106
- type FerixError = LLMError | ParseError | PlanStoreError | SessionStoreError | ProgressStoreError | GuardrailsStoreError | OrchestratorError | GitError;
150
+ type FerixError = LLMError | ParseError | PlanStoreError | SessionStoreError | ProgressStoreError | GuardrailsStoreError | OrchestratorError | GitError | TokenBudgetError | RetryExhaustedError | MetricsError;
107
151
 
108
152
  /**
109
153
  * Text delta event - streamed text content.
@@ -699,6 +743,8 @@ declare const LoopSummarySchema: Schema.Struct<{
699
743
  sessionId: typeof Schema.String;
700
744
  completedTasks: Schema.Array$<typeof Schema.String>;
701
745
  durationMs: typeof Schema.Number;
746
+ branchPushed: Schema.optional<typeof Schema.Boolean>;
747
+ prUrl: Schema.optional<typeof Schema.String>;
702
748
  }>;
703
749
  type LoopSummary = typeof LoopSummarySchema.Type;
704
750
  declare const LoopErrorSchema: Schema.Struct<{
@@ -770,6 +816,8 @@ declare const LoopCompletedEventSchema: Schema.TaggedStruct<"LoopCompleted", {
770
816
  sessionId: typeof Schema.String;
771
817
  completedTasks: Schema.Array$<typeof Schema.String>;
772
818
  durationMs: typeof Schema.Number;
819
+ branchPushed: Schema.optional<typeof Schema.Boolean>;
820
+ prUrl: Schema.optional<typeof Schema.String>;
773
821
  }>;
774
822
  }>;
775
823
  type LoopCompletedEvent = typeof LoopCompletedEventSchema.Type;
@@ -1024,6 +1072,25 @@ declare const WorktreeRemovedEventSchema: Schema.TaggedStruct<"WorktreeRemoved",
1024
1072
  timestamp: typeof Schema.Number;
1025
1073
  }>;
1026
1074
  type WorktreeRemovedEvent = typeof WorktreeRemovedEventSchema.Type;
1075
+ /**
1076
+ * Branch pushed event - signals that a branch was pushed to origin.
1077
+ */
1078
+ declare const BranchPushedEventSchema: Schema.TaggedStruct<"BranchPushed", {
1079
+ sessionId: typeof Schema.String;
1080
+ branchName: typeof Schema.String;
1081
+ timestamp: typeof Schema.Number;
1082
+ }>;
1083
+ type BranchPushedEvent = typeof BranchPushedEventSchema.Type;
1084
+ /**
1085
+ * PR created event - signals that a pull request was created.
1086
+ */
1087
+ declare const PRCreatedEventSchema: Schema.TaggedStruct<"PRCreated", {
1088
+ sessionId: typeof Schema.String;
1089
+ prUrl: typeof Schema.String;
1090
+ title: typeof Schema.String;
1091
+ timestamp: typeof Schema.Number;
1092
+ }>;
1093
+ type PRCreatedEvent = typeof PRCreatedEventSchema.Type;
1027
1094
  /**
1028
1095
  * Session name generated event - signals that the LLM generated a descriptive name for the session.
1029
1096
  * Emitted during the discovery phase after the session name signal is parsed.
@@ -1071,6 +1138,8 @@ declare const DomainEventSchema: Schema.Union<[Schema.TaggedStruct<"LoopStarted"
1071
1138
  sessionId: typeof Schema.String;
1072
1139
  completedTasks: Schema.Array$<typeof Schema.String>;
1073
1140
  durationMs: typeof Schema.Number;
1141
+ branchPushed: Schema.optional<typeof Schema.Boolean>;
1142
+ prUrl: Schema.optional<typeof Schema.String>;
1074
1143
  }>;
1075
1144
  }>, Schema.TaggedStruct<"LoopFailed", {
1076
1145
  error: Schema.Struct<{
@@ -1220,6 +1289,15 @@ declare const DomainEventSchema: Schema.Union<[Schema.TaggedStruct<"LoopStarted"
1220
1289
  }>, Schema.TaggedStruct<"WorktreeRemoved", {
1221
1290
  sessionId: typeof Schema.String;
1222
1291
  timestamp: typeof Schema.Number;
1292
+ }>, Schema.TaggedStruct<"BranchPushed", {
1293
+ sessionId: typeof Schema.String;
1294
+ branchName: typeof Schema.String;
1295
+ timestamp: typeof Schema.Number;
1296
+ }>, Schema.TaggedStruct<"PRCreated", {
1297
+ sessionId: typeof Schema.String;
1298
+ prUrl: typeof Schema.String;
1299
+ title: typeof Schema.String;
1300
+ timestamp: typeof Schema.Number;
1223
1301
  }>, Schema.TaggedStruct<"SessionNameGenerated", {
1224
1302
  sessionId: typeof Schema.String;
1225
1303
  /** Task-based descriptive name (kebab-case slug, e.g., "add-dark-mode-toggle") */
@@ -1229,7 +1307,7 @@ declare const DomainEventSchema: Schema.Union<[Schema.TaggedStruct<"LoopStarted"
1229
1307
  /**
1230
1308
  * Explicit discriminated union type for proper TypeScript narrowing.
1231
1309
  */
1232
- type DomainEvent = LoopStartedEvent | LoopCompletedEvent | LoopFailedEvent | DiscoveryStartedEvent | DiscoveryCompletedEvent | IterationStartedEvent | IterationCompletedEvent | LLMTextEvent | LLMToolStartEvent | LLMToolUseEvent | LLMToolEndEvent | TasksDefinedEvent | PhasesDefinedEvent | CriteriaDefinedEvent | PhaseStartedEvent | PhaseCompletedEvent | PhaseFailedEvent | CriterionPassedEvent | CriterionFailedEvent | CheckPassedEvent | CheckFailedEvent | ReviewCompleteEvent | TaskCompletedEvent | PlanCreatedEvent | PlanUpdatedEvent | PlanUpdateFailedEvent | LearningRecordedEvent | GuardrailAddedEvent | ProgressUpdatedEvent | WorktreeCreatedEvent | WorktreeRemovedEvent | SessionNameGeneratedEvent;
1310
+ type DomainEvent = LoopStartedEvent | LoopCompletedEvent | LoopFailedEvent | DiscoveryStartedEvent | DiscoveryCompletedEvent | IterationStartedEvent | IterationCompletedEvent | LLMTextEvent | LLMToolStartEvent | LLMToolUseEvent | LLMToolEndEvent | TasksDefinedEvent | PhasesDefinedEvent | CriteriaDefinedEvent | PhaseStartedEvent | PhaseCompletedEvent | PhaseFailedEvent | CriterionPassedEvent | CriterionFailedEvent | CheckPassedEvent | CheckFailedEvent | ReviewCompleteEvent | TaskCompletedEvent | PlanCreatedEvent | PlanUpdatedEvent | PlanUpdateFailedEvent | LearningRecordedEvent | GuardrailAddedEvent | ProgressUpdatedEvent | WorktreeCreatedEvent | WorktreeRemovedEvent | BranchPushedEvent | PRCreatedEvent | SessionNameGeneratedEvent;
1233
1311
  /**
1234
1312
  * Type guard utilities for domain events.
1235
1313
  */
@@ -1830,6 +1908,7 @@ declare const decodePlan: (u: unknown, overrideOptions?: effect_SchemaAST.ParseO
1830
1908
  readonly description: string;
1831
1909
  }[];
1832
1910
  readonly status: "planning" | "pending" | "in_progress" | "done" | "failed" | "skipped";
1911
+ readonly attempts: number;
1833
1912
  readonly id: string;
1834
1913
  readonly description: string;
1835
1914
  readonly title: string;
@@ -1840,7 +1919,6 @@ declare const decodePlan: (u: unknown, overrideOptions?: effect_SchemaAST.ParseO
1840
1919
  readonly failureReason?: string | undefined;
1841
1920
  }[];
1842
1921
  readonly filesToModify: readonly string[];
1843
- readonly attempts: number;
1844
1922
  readonly completionNotes?: string | undefined;
1845
1923
  }[];
1846
1924
  }, effect_ParseResult.ParseError, never>;
@@ -1856,6 +1934,7 @@ declare const decodePlanData: (u: unknown, overrideOptions?: effect_SchemaAST.Pa
1856
1934
  readonly description: string;
1857
1935
  }[];
1858
1936
  readonly status: "planning" | "pending" | "in_progress" | "done" | "failed" | "skipped";
1937
+ readonly attempts: number;
1859
1938
  readonly id: string;
1860
1939
  readonly description: string;
1861
1940
  readonly title: string;
@@ -1866,7 +1945,6 @@ declare const decodePlanData: (u: unknown, overrideOptions?: effect_SchemaAST.Pa
1866
1945
  readonly failureReason?: string | undefined;
1867
1946
  }[];
1868
1947
  readonly filesToModify: readonly string[];
1869
- readonly attempts: number;
1870
1948
  readonly completionNotes?: string | undefined;
1871
1949
  }[];
1872
1950
  }, effect_ParseResult.ParseError, never>;
@@ -1992,6 +2070,8 @@ declare const SessionSchema: Schema.Struct<{
1992
2070
  branchName: Schema.optional<typeof Schema.String>;
1993
2071
  /** Task-based descriptive name (kebab-case slug, e.g., "add-dark-mode-toggle") */
1994
2072
  displayName: Schema.optional<typeof Schema.String>;
2073
+ /** The branch ferix was started from - used as PR base branch */
2074
+ baseBranch: Schema.optional<typeof Schema.String>;
1995
2075
  }>;
1996
2076
  type Session = typeof SessionSchema.Type;
1997
2077
  /**
@@ -2007,6 +2087,7 @@ declare const decodeSession: (u: unknown, overrideOptions?: effect_SchemaAST.Par
2007
2087
  readonly branchName?: string | undefined;
2008
2088
  readonly displayName?: string | undefined;
2009
2089
  readonly currentTaskId?: string | undefined;
2090
+ readonly baseBranch?: string | undefined;
2010
2091
  }, effect_ParseResult.ParseError, never>;
2011
2092
 
2012
2093
  /**
@@ -2926,9 +3007,18 @@ interface GitService {
2926
3007
  * @param sessionId - Session ID whose branch to create PR for
2927
3008
  * @param title - PR title
2928
3009
  * @param body - PR body/description
3010
+ * @param baseBranch - Optional base branch for the PR (defaults to repo default)
2929
3011
  * @returns URL of the created PR
2930
3012
  */
2931
- readonly createPR: (sessionId: string, title: string, body: string) => Effect.Effect<PrUrl, GitError>;
3013
+ readonly createPR: (sessionId: string, title: string, body: string, baseBranch?: string) => Effect.Effect<PrUrl, GitError>;
3014
+ /**
3015
+ * Get the current branch name of the main repository.
3016
+ *
3017
+ * Used to capture the base branch when starting a session.
3018
+ *
3019
+ * @returns The current branch name
3020
+ */
3021
+ readonly getCurrentBranch: () => Effect.Effect<string, GitError>;
2932
3022
  /**
2933
3023
  * Get the branch name for a session.
2934
3024
  *
@@ -3783,4 +3873,4 @@ declare function collectEvents(config: LoopConfig, mockEvents?: readonly LLMEven
3783
3873
  */
3784
3874
  declare function main(config: LoopConfig): Promise<void>;
3785
3875
 
3786
- export { type AnyToolInput, AnyToolInputSchema, type AssistantMessage, AssistantMessageSchema, type BashToolInput, BashToolInputSchema, type CheckFailedEvent, CheckFailedEventSchema, type CheckFailedSignal, CheckFailedSignalSchema, type CheckPassedEvent, CheckPassedEventSchema, type CheckPassedSignal, CheckPassedSignalSchema, ClaudeCLI, type ClaudeCliEvent, ClaudeCliEventSchema, type CommitHash, type ConsoleLoggerConfig, ConsoleLoggerConfigSchema, type Consumer, type ConsumerType, ConsumerTypeSchema, type ContentBlock, type ContentBlockDelta, ContentBlockDeltaSchema, ContentBlockSchema, type ContentBlockStart, ContentBlockStartSchema, type ContentBlockStop, ContentBlockStopSchema, type CriteriaDefinedData, CriteriaDefinedDataSchema, type CriteriaDefinedEvent, CriteriaDefinedEventSchema, type CriteriaDefinedSignal, CriteriaDefinedSignalSchema, type Criterion, type CriterionBasicInfo, CriterionBasicInfoSchema, type CriterionFailedData, CriterionFailedDataSchema, type CriterionFailedEvent, CriterionFailedEventSchema, type CriterionFailedSignal, CriterionFailedSignalSchema, type CriterionIdData, CriterionIdDataSchema, type CriterionPassedEvent, CriterionPassedEventSchema, type CriterionPassedSignal, CriterionPassedSignalSchema, CriterionSchema, type CriterionStatus, CriterionStatusSchema, CursorCLI, type Delta, DeltaSchema, type DiscoveryCompletedEvent, DiscoveryCompletedEventSchema, type DiscoveryStartedEvent, DiscoveryStartedEventSchema, type DomainEvent, DomainEventSchema, DomainEventUtils, type DoneEvent, DoneEventSchema, type EditToolInput, EditToolInputSchema, type ExecutionMode, ExecutionModeSchema, type FerixError, FerixParser, type FileLoggerConfig, FileLoggerConfigSchema, FileSystemGit, FileSystemGuardrails, FileSystemPlan, FileSystemProgress, FileSystemSession, type GeneratedTask, type GeneratedTaskList, GeneratedTaskListSchema, GeneratedTaskSchema, type GeneratedTaskStatus, GeneratedTaskStatusSchema, Git, GitError, type GitService, type GlobToolInput, GlobToolInputSchema, type GrepToolInput, GrepToolInputSchema, type Guardrail, type GuardrailAddedEvent, GuardrailAddedEventSchema, GuardrailSchema, type GuardrailSeverity, GuardrailSeveritySchema, type GuardrailSignal, GuardrailSignalSchema, type GuardrailsFile, GuardrailsFileSchema, GuardrailsStore, GuardrailsStoreError, type GuardrailsStoreService, type InputJsonDelta, InputJsonDeltaSchema, type IterationCompletedEvent, IterationCompletedEventSchema, type IterationStartedEvent, IterationStartedEventSchema, type KnownToolName, LLM, LLMError, type LLMEvent, LLMEventSchema, type LLMExecuteOptions, type LLMService, type LLMTextEvent, LLMTextEventSchema, type LLMToolEndEvent, LLMToolEndEventSchema, type LLMToolStartEvent, LLMToolStartEventSchema, type LLMToolUseEvent, LLMToolUseEventSchema, type LearningCategory, LearningCategorySchema, type LearningRecordedEvent, LearningRecordedEventSchema, type LearningSignal, LearningSignalSchema, type LogEntry, LogEntrySchema, type LogLevel, LogLevelSchema, type LoopCompleteSignal, LoopCompleteSignalSchema, type LoopCompletedEvent, LoopCompletedEventSchema, type LoopConfig, LoopConfigSchema, type LoopError, LoopErrorSchema, type LoopFailedEvent, LoopFailedEventSchema, type LoopStartedEvent, LoopStartedEventSchema, type LoopStatus, LoopStatusSchema, type LoopSummary, LoopSummarySchema, MemoryGit, MemoryGuardrails, MemoryPlan, MemoryProgress, MemorySession, Mock, Mock as MockLLM, type OpenCodeCliEvent, OpenCodeCliEventSchema, type OpenCodeCost, OpenCodeCostSchema, type OpenCodeStepFinish, OpenCodeStepFinishSchema, type OpenCodeStepPart, OpenCodeStepPartSchema, type OpenCodeStepStart, OpenCodeStepStartSchema, type OpenCodeTextEvent, OpenCodeTextEventSchema, type OpenCodeTokens, OpenCodeTokensSchema, type OpenCodeToolPart, OpenCodeToolPartSchema, type OpenCodeToolState, OpenCodeToolStateSchema, type OpenCodeToolUseEvent, OpenCodeToolUseEventSchema, OrchestratorError, type OrchestratorServices, PROVIDER_CONFIGS, ParseError, type Phase, type PhaseBasicInfo, PhaseBasicInfoSchema, type PhaseCompletedEvent, PhaseCompletedEventSchema, type PhaseCompletedSignal, PhaseCompletedSignalSchema, type PhaseFailedData, PhaseFailedDataSchema, type PhaseFailedEvent, PhaseFailedEventSchema, type PhaseFailedSignal, PhaseFailedSignalSchema, type PhaseIdData, PhaseIdDataSchema, type PhasePromptOverrides, PhasePromptOverridesSchema, PhaseSchema, type PhaseStartedEvent, PhaseStartedEventSchema, type PhaseStartedSignal, PhaseStartedSignalSchema, type PhaseStatus, PhaseStatusSchema, type PhasesDefinedData, PhasesDefinedDataSchema, type PhasesDefinedEvent, PhasesDefinedEventSchema, type PhasesDefinedSignal, PhasesDefinedSignalSchema, type Plan, type PlanCreatedEvent, PlanCreatedEventSchema, type PlanData, PlanDataSchema, PlanId, PlanSchema, PlanStore, PlanStoreError, type PlanStoreService, type PlanUpdateFailedEvent, PlanUpdateFailedEventSchema, type PlanUpdatedEvent, PlanUpdatedEventSchema, type PrUrl, ProductionLayers, type ProgressAction, ProgressActionSchema, type ProgressEntry, ProgressEntrySchema, type ProgressFile, ProgressFileSchema, ProgressStore, ProgressStoreError, type ProgressStoreService, type ProgressUpdatedEvent, ProgressUpdatedEventSchema, type PromptConfig, PromptConfigSchema, type Provider, type ProviderConfig, type ProviderName, ProviderNameSchema, type ReadToolInput, ReadToolInputSchema, type ReviewCompleteData, ReviewCompleteDataSchema, type ReviewCompleteEvent, ReviewCompleteEventSchema, type ReviewCompleteSignal, ReviewCompleteSignalSchema, type RunOptions, type RunOptionsData, RunOptionsDataSchema, type Session, type SessionNameDefinedSignal, SessionNameDefinedSignalSchema, type SessionNameGeneratedEvent, SessionNameGeneratedEventSchema, SessionSchema, type SessionStatus, SessionStatusSchema, SessionStore, SessionStoreError, type SessionStoreService, type Signal, type SignalAccumulator, SignalParser, type SignalParserService, SignalSchema, type StreamEventEnvelope, StreamEventEnvelopeSchema, type TUICriterion, TUICriterionSchema, type TUICriterionStatus, TUICriterionStatusSchema, type TUIPhase, TUIPhaseSchema, type TUIPhaseStatus, TUIPhaseStatusSchema, type TUIState, TUIStateSchema, type TUITask, TUITaskSchema, type TUITaskStatus, TUITaskStatusSchema, type Task, type TaskBasicInfo, TaskBasicInfoSchema, type TaskCompleteData, TaskCompleteDataSchema, type TaskCompleteSignal, type TaskCompleteSignalData, TaskCompleteSignalDataSchema, TaskCompleteSignalSchema, type TaskCompletedEvent, TaskCompletedEventSchema, TaskSchema, type TaskStatus, TaskStatusSchema, type TaskToolInput, TaskToolInputSchema, type TasksDefinedData, TasksDefinedDataSchema, type TasksDefinedEvent, TasksDefinedEventSchema, type TasksDefinedSignal, TasksDefinedSignalSchema, TestLayers, type TextContentBlock, TextContentBlockSchema, type TextDelta, TextDeltaSchema, type TextEvent, TextEventSchema, type ToolEndEvent, ToolEndEventSchema, ToolInputSchemaRegistry, type ToolStartEvent, ToolStartEventSchema, type ToolUseContentBlock, ToolUseContentBlockSchema, type ToolUseEvent, ToolUseEventSchema, type ValidatedToolUseEvent, ValidatedToolUseEventSchema, type ViewMode, ViewModeSchema, type WebFetchToolInput, WebFetchToolInputSchema, type WebSearchToolInput, WebSearchToolInputSchema, type WorktreeCreatedEvent, WorktreeCreatedEventSchema, type WorktreeInfo, type WorktreePath, type WorktreeRemovedEvent, WorktreeRemovedEventSchema, type WriteToolInput, WriteToolInputSchema, buildPrompt, collectEvents, createCheckFailedSignal, createCheckPassedSignal, createCriteriaDefinedSignal, createCriterionFailedSignal, createCriterionPassedSignal, createGuardrailSignal, createHeadlessConsumer, createLearningSignal, createLoopCompleteSignal, createPhaseCompletedSignal, createPhaseFailedSignal, createPhaseStartedSignal, createPhasesDefinedSignal, createProductionLayers, createProviderLayer, createReviewCompleteSignal, createSessionNameDefinedSignal, createTUIConsumer, createTaskCompleteSignal, createTasksDefinedSignal, createTestLayers, decodeClaudeCliEvent, decodeClaudeCliEventSync, decodeGuardrail, decodeGuardrailsFile, decodeLLMEvent, decodeLoopConfig, decodeOpenCodeCliEvent, decodeOpenCodeCliEventSync, decodePlan, decodePlanData, decodeProgressEntry, decodeProgressFile, decodeSession, decodeSignal, decodeSignalSync, formatTasksMd, getToolInputSchema, isAssistantMessage, isBashToolInput, isContentBlockDelta, isContentBlockStart, isContentBlockStop, isEditToolInput, isGlobToolInput, isGrepToolInput, isInputJsonDelta, isOpenCodeStepFinish, isOpenCodeStepStart, isOpenCodeTextEvent, isOpenCodeToolUseEvent, isReadToolInput, isStreamEventEnvelope, isTaskToolInput, isTextContentBlock, isTextDelta, isToolUseContentBlock, isWebFetchToolInput, isWebSearchToolInput, isWriteToolInput, main, parseTasksMd, run, runLoop, runTest, validateToolInput, validateToolUseEvent };
3876
+ export { type AnyToolInput, AnyToolInputSchema, type AssistantMessage, AssistantMessageSchema, type BashToolInput, BashToolInputSchema, type BranchPushedEvent, BranchPushedEventSchema, type CheckFailedEvent, CheckFailedEventSchema, type CheckFailedSignal, CheckFailedSignalSchema, type CheckPassedEvent, CheckPassedEventSchema, type CheckPassedSignal, CheckPassedSignalSchema, ClaudeCLI, type ClaudeCliEvent, ClaudeCliEventSchema, type CommitHash, type ConsoleLoggerConfig, ConsoleLoggerConfigSchema, type Consumer, type ConsumerType, ConsumerTypeSchema, type ContentBlock, type ContentBlockDelta, ContentBlockDeltaSchema, ContentBlockSchema, type ContentBlockStart, ContentBlockStartSchema, type ContentBlockStop, ContentBlockStopSchema, type CriteriaDefinedData, CriteriaDefinedDataSchema, type CriteriaDefinedEvent, CriteriaDefinedEventSchema, type CriteriaDefinedSignal, CriteriaDefinedSignalSchema, type Criterion, type CriterionBasicInfo, CriterionBasicInfoSchema, type CriterionFailedData, CriterionFailedDataSchema, type CriterionFailedEvent, CriterionFailedEventSchema, type CriterionFailedSignal, CriterionFailedSignalSchema, type CriterionIdData, CriterionIdDataSchema, type CriterionPassedEvent, CriterionPassedEventSchema, type CriterionPassedSignal, CriterionPassedSignalSchema, CriterionSchema, type CriterionStatus, CriterionStatusSchema, CursorCLI, type Delta, DeltaSchema, type DiscoveryCompletedEvent, DiscoveryCompletedEventSchema, type DiscoveryStartedEvent, DiscoveryStartedEventSchema, type DomainEvent, DomainEventSchema, DomainEventUtils, type DoneEvent, DoneEventSchema, type EditToolInput, EditToolInputSchema, type ExecutionMode, ExecutionModeSchema, type FerixError, FerixParser, type FileLoggerConfig, FileLoggerConfigSchema, FileSystemGit, FileSystemGuardrails, FileSystemPlan, FileSystemProgress, FileSystemSession, type GeneratedTask, type GeneratedTaskList, GeneratedTaskListSchema, GeneratedTaskSchema, type GeneratedTaskStatus, GeneratedTaskStatusSchema, Git, GitError, type GitService, type GlobToolInput, GlobToolInputSchema, type GrepToolInput, GrepToolInputSchema, type Guardrail, type GuardrailAddedEvent, GuardrailAddedEventSchema, GuardrailSchema, type GuardrailSeverity, GuardrailSeveritySchema, type GuardrailSignal, GuardrailSignalSchema, type GuardrailsFile, GuardrailsFileSchema, GuardrailsStore, GuardrailsStoreError, type GuardrailsStoreService, type InputJsonDelta, InputJsonDeltaSchema, type IterationCompletedEvent, IterationCompletedEventSchema, type IterationStartedEvent, IterationStartedEventSchema, type KnownToolName, LLM, LLMError, type LLMEvent, LLMEventSchema, type LLMExecuteOptions, type LLMService, type LLMTextEvent, LLMTextEventSchema, type LLMToolEndEvent, LLMToolEndEventSchema, type LLMToolStartEvent, LLMToolStartEventSchema, type LLMToolUseEvent, LLMToolUseEventSchema, type LearningCategory, LearningCategorySchema, type LearningRecordedEvent, LearningRecordedEventSchema, type LearningSignal, LearningSignalSchema, type LogEntry, LogEntrySchema, type LogLevel, LogLevelSchema, type LoopCompleteSignal, LoopCompleteSignalSchema, type LoopCompletedEvent, LoopCompletedEventSchema, type LoopConfig, LoopConfigSchema, type LoopError, LoopErrorSchema, type LoopFailedEvent, LoopFailedEventSchema, type LoopStartedEvent, LoopStartedEventSchema, type LoopStatus, LoopStatusSchema, type LoopSummary, LoopSummarySchema, MemoryGit, MemoryGuardrails, MemoryPlan, MemoryProgress, MemorySession, MetricsError, Mock, Mock as MockLLM, type OpenCodeCliEvent, OpenCodeCliEventSchema, type OpenCodeCost, OpenCodeCostSchema, type OpenCodeStepFinish, OpenCodeStepFinishSchema, type OpenCodeStepPart, OpenCodeStepPartSchema, type OpenCodeStepStart, OpenCodeStepStartSchema, type OpenCodeTextEvent, OpenCodeTextEventSchema, type OpenCodeTokens, OpenCodeTokensSchema, type OpenCodeToolPart, OpenCodeToolPartSchema, type OpenCodeToolState, OpenCodeToolStateSchema, type OpenCodeToolUseEvent, OpenCodeToolUseEventSchema, OrchestratorError, type OrchestratorServices, type PRCreatedEvent, PRCreatedEventSchema, PROVIDER_CONFIGS, ParseError, type Phase, type PhaseBasicInfo, PhaseBasicInfoSchema, type PhaseCompletedEvent, PhaseCompletedEventSchema, type PhaseCompletedSignal, PhaseCompletedSignalSchema, type PhaseFailedData, PhaseFailedDataSchema, type PhaseFailedEvent, PhaseFailedEventSchema, type PhaseFailedSignal, PhaseFailedSignalSchema, type PhaseIdData, PhaseIdDataSchema, type PhasePromptOverrides, PhasePromptOverridesSchema, PhaseSchema, type PhaseStartedEvent, PhaseStartedEventSchema, type PhaseStartedSignal, PhaseStartedSignalSchema, type PhaseStatus, PhaseStatusSchema, type PhasesDefinedData, PhasesDefinedDataSchema, type PhasesDefinedEvent, PhasesDefinedEventSchema, type PhasesDefinedSignal, PhasesDefinedSignalSchema, type Plan, type PlanCreatedEvent, PlanCreatedEventSchema, type PlanData, PlanDataSchema, PlanId, PlanSchema, PlanStore, PlanStoreError, type PlanStoreService, type PlanUpdateFailedEvent, PlanUpdateFailedEventSchema, type PlanUpdatedEvent, PlanUpdatedEventSchema, type PrUrl, ProductionLayers, type ProgressAction, ProgressActionSchema, type ProgressEntry, ProgressEntrySchema, type ProgressFile, ProgressFileSchema, ProgressStore, ProgressStoreError, type ProgressStoreService, type ProgressUpdatedEvent, ProgressUpdatedEventSchema, type PromptConfig, PromptConfigSchema, type Provider, type ProviderConfig, type ProviderName, ProviderNameSchema, type ReadToolInput, ReadToolInputSchema, RetryExhaustedError, type ReviewCompleteData, ReviewCompleteDataSchema, type ReviewCompleteEvent, ReviewCompleteEventSchema, type ReviewCompleteSignal, ReviewCompleteSignalSchema, type RunOptions, type RunOptionsData, RunOptionsDataSchema, type Session, type SessionNameDefinedSignal, SessionNameDefinedSignalSchema, type SessionNameGeneratedEvent, SessionNameGeneratedEventSchema, SessionSchema, type SessionStatus, SessionStatusSchema, SessionStore, SessionStoreError, type SessionStoreService, type Signal, type SignalAccumulator, SignalParser, type SignalParserService, SignalSchema, type StreamEventEnvelope, StreamEventEnvelopeSchema, type TUICriterion, TUICriterionSchema, type TUICriterionStatus, TUICriterionStatusSchema, type TUIPhase, TUIPhaseSchema, type TUIPhaseStatus, TUIPhaseStatusSchema, type TUIState, TUIStateSchema, type TUITask, TUITaskSchema, type TUITaskStatus, TUITaskStatusSchema, type Task, type TaskBasicInfo, TaskBasicInfoSchema, type TaskCompleteData, TaskCompleteDataSchema, type TaskCompleteSignal, type TaskCompleteSignalData, TaskCompleteSignalDataSchema, TaskCompleteSignalSchema, type TaskCompletedEvent, TaskCompletedEventSchema, TaskSchema, type TaskStatus, TaskStatusSchema, type TaskToolInput, TaskToolInputSchema, type TasksDefinedData, TasksDefinedDataSchema, type TasksDefinedEvent, TasksDefinedEventSchema, type TasksDefinedSignal, TasksDefinedSignalSchema, TestLayers, type TextContentBlock, TextContentBlockSchema, type TextDelta, TextDeltaSchema, type TextEvent, TextEventSchema, TokenBudgetError, type ToolEndEvent, ToolEndEventSchema, ToolInputSchemaRegistry, type ToolStartEvent, ToolStartEventSchema, type ToolUseContentBlock, ToolUseContentBlockSchema, type ToolUseEvent, ToolUseEventSchema, type ValidatedToolUseEvent, ValidatedToolUseEventSchema, type ViewMode, ViewModeSchema, type WebFetchToolInput, WebFetchToolInputSchema, type WebSearchToolInput, WebSearchToolInputSchema, type WorktreeCreatedEvent, WorktreeCreatedEventSchema, type WorktreeInfo, type WorktreePath, type WorktreeRemovedEvent, WorktreeRemovedEventSchema, type WriteToolInput, WriteToolInputSchema, buildPrompt, collectEvents, createCheckFailedSignal, createCheckPassedSignal, createCriteriaDefinedSignal, createCriterionFailedSignal, createCriterionPassedSignal, createGuardrailSignal, createHeadlessConsumer, createLearningSignal, createLoopCompleteSignal, createPhaseCompletedSignal, createPhaseFailedSignal, createPhaseStartedSignal, createPhasesDefinedSignal, createProductionLayers, createProviderLayer, createReviewCompleteSignal, createSessionNameDefinedSignal, createTUIConsumer, createTaskCompleteSignal, createTasksDefinedSignal, createTestLayers, decodeClaudeCliEvent, decodeClaudeCliEventSync, decodeGuardrail, decodeGuardrailsFile, decodeLLMEvent, decodeLoopConfig, decodeOpenCodeCliEvent, decodeOpenCodeCliEventSync, decodePlan, decodePlanData, decodeProgressEntry, decodeProgressFile, decodeSession, decodeSignal, decodeSignalSync, formatTasksMd, getToolInputSchema, isAssistantMessage, isBashToolInput, isContentBlockDelta, isContentBlockStart, isContentBlockStop, isEditToolInput, isGlobToolInput, isGrepToolInput, isInputJsonDelta, isOpenCodeStepFinish, isOpenCodeStepStart, isOpenCodeTextEvent, isOpenCodeToolUseEvent, isReadToolInput, isStreamEventEnvelope, isTaskToolInput, isTextContentBlock, isTextDelta, isToolUseContentBlock, isWebFetchToolInput, isWebSearchToolInput, isWriteToolInput, main, parseTasksMd, run, runLoop, runTest, validateToolInput, validateToolUseEvent };
package/dist/index.js CHANGED
@@ -66,12 +66,15 @@ var init_registry = __esm({
66
66
 
67
67
  // src/index.ts
68
68
  init_esm_shims();
69
+ import { sync } from "@ferix/sync";
69
70
  import { Command } from "commander";
71
+ import { Effect as Effect25 } from "effect";
72
+ import pc17 from "picocolors";
70
73
 
71
74
  // package.json
72
75
  var package_default = {
73
76
  name: "ferix-code",
74
- version: "0.0.2-beta.18",
77
+ version: "0.0.2-beta.20",
75
78
  description: "Composable RALPH loops for AI coding agents - v2 with Effect",
76
79
  type: "module",
77
80
  bin: {
@@ -90,6 +93,7 @@ var package_default = {
90
93
  bump: "npm version prerelease --preid=beta --workspaces=false && bun run build && bun publish --tag beta"
91
94
  },
92
95
  dependencies: {
96
+ "@ferix/sync": "*",
93
97
  commander: "^14.0.0",
94
98
  effect: "^3.19.15",
95
99
  "human-id": "^4.1.3",
@@ -905,6 +909,17 @@ tagRendererRegistry.register({
905
909
  render: () => `${colors.info(symbols.bulletFilled)} ${colors.muted("Review made changes")}`
906
910
  });
907
911
 
912
+ // src/consumers/tui/tags/handlers/session-name.ts
913
+ init_esm_shims();
914
+ init_registry();
915
+ tagRendererRegistry.register({
916
+ pattern: /<ferix:session-name>([^<]+)<\/ferix:session-name>/g,
917
+ render: (m) => {
918
+ const name = m[1] ?? "";
919
+ return `${colors.brand(symbols.diamond)} ${colors.muted(name)}`;
920
+ }
921
+ });
922
+
908
923
  // src/consumers/tui/tags/handlers/tasks.ts
909
924
  init_esm_shims();
910
925
  init_registry();
@@ -2560,7 +2575,14 @@ import { Layer as Layer14 } from "effect";
2560
2575
  // src/layers/git/file-system.ts
2561
2576
  init_esm_shims();
2562
2577
  import { exec } from "child_process";
2563
- import { access, copyFile, mkdir, rm } from "fs/promises";
2578
+ import {
2579
+ access,
2580
+ appendFile,
2581
+ copyFile,
2582
+ mkdir,
2583
+ readFile,
2584
+ rm
2585
+ } from "fs/promises";
2564
2586
  import { dirname, join } from "path";
2565
2587
  import { promisify } from "util";
2566
2588
  import { Effect as Effect4, Layer } from "effect";
@@ -2586,6 +2608,14 @@ var OrchestratorError = class extends Data.TaggedError("OrchestratorError") {
2586
2608
  };
2587
2609
  var GitError = class extends Data.TaggedError("GitError") {
2588
2610
  };
2611
+ var TokenBudgetError = class extends Data.TaggedError("TokenBudgetError") {
2612
+ };
2613
+ var RetryExhaustedError = class extends Data.TaggedError(
2614
+ "RetryExhaustedError"
2615
+ ) {
2616
+ };
2617
+ var MetricsError = class extends Data.TaggedError("MetricsError") {
2618
+ };
2589
2619
 
2590
2620
  // src/services/git.ts
2591
2621
  init_esm_shims();
@@ -2596,6 +2626,7 @@ var Git = class extends Context.Tag("@ferix/Git")() {
2596
2626
  // src/layers/git/file-system.ts
2597
2627
  var execAsync = promisify(exec);
2598
2628
  var WORKTREES_DIR = ".ferix/worktrees";
2629
+ var GITDIR_REGEX = /^gitdir:\s*(.+)$/m;
2599
2630
  var BRANCH_PREFIX = "ferix";
2600
2631
  function getWorktreeDir(sessionId) {
2601
2632
  return join(process.cwd(), WORKTREES_DIR, sessionId);
@@ -2628,12 +2659,39 @@ function directoryExists(dirPath) {
2628
2659
  catch: () => new Error("Directory does not exist")
2629
2660
  }).pipe(Effect4.orElseSucceed(() => false));
2630
2661
  }
2662
+ function branchExists(branchName) {
2663
+ return gitExec(`git rev-parse --verify refs/heads/${branchName}`).pipe(
2664
+ Effect4.map(() => true),
2665
+ Effect4.orElseSucceed(() => false)
2666
+ );
2667
+ }
2668
+ function findAvailableBranchName(baseName, maxAttempts = 100) {
2669
+ const tryName = (name, attempt) => Effect4.gen(function* () {
2670
+ const exists = yield* branchExists(name);
2671
+ if (!exists) {
2672
+ return name;
2673
+ }
2674
+ if (attempt >= maxAttempts) {
2675
+ return yield* Effect4.fail(
2676
+ new GitError({
2677
+ message: `Could not find available branch name after ${maxAttempts} attempts`,
2678
+ operation: "branchLookup"
2679
+ })
2680
+ );
2681
+ }
2682
+ return yield* tryName(`${baseName}-${attempt + 1}`, attempt + 1);
2683
+ });
2684
+ return tryName(baseName, 1);
2685
+ }
2631
2686
  function copyUntrackedFiles(worktreeDir) {
2632
2687
  return Effect4.gen(function* () {
2633
2688
  const untrackedOutput = yield* gitExec(
2634
2689
  "git ls-files --others --exclude-standard"
2635
2690
  ).pipe(Effect4.catchAll(() => Effect4.succeed("")));
2636
2691
  const untrackedFiles = untrackedOutput.split("\n").filter((f) => f.length > 0).filter((f) => !f.startsWith(".ferix/"));
2692
+ if (untrackedFiles.length === 0) {
2693
+ return;
2694
+ }
2637
2695
  for (const file of untrackedFiles) {
2638
2696
  const srcPath = join(process.cwd(), file);
2639
2697
  const destPath = join(worktreeDir, file);
@@ -2648,6 +2706,26 @@ function copyUntrackedFiles(worktreeDir) {
2648
2706
  })
2649
2707
  }).pipe(Effect4.catchAll(() => Effect4.succeed(void 0)));
2650
2708
  }
2709
+ yield* Effect4.tryPromise({
2710
+ try: async () => {
2711
+ const gitFilePath = join(worktreeDir, ".git");
2712
+ const gitFileContent = await readFile(gitFilePath, "utf-8");
2713
+ const gitDirMatch = gitFileContent.match(GITDIR_REGEX);
2714
+ const gitDirPath = gitDirMatch?.[1]?.trim();
2715
+ if (!gitDirPath) {
2716
+ return;
2717
+ }
2718
+ const gitDir = gitDirPath;
2719
+ const excludePath = join(gitDir, "info", "exclude");
2720
+ await mkdir(dirname(excludePath), { recursive: true });
2721
+ const excludeContent = "\n# Untracked files copied from main worktree (auto-generated by ferix)\n" + untrackedFiles.join("\n") + "\n";
2722
+ await appendFile(excludePath, excludeContent);
2723
+ },
2724
+ catch: () => new GitError({
2725
+ message: "Failed to update exclude file for copied untracked files",
2726
+ operation: "createWorktree"
2727
+ })
2728
+ }).pipe(Effect4.catchAll(() => Effect4.succeed(void 0)));
2651
2729
  });
2652
2730
  }
2653
2731
  var make = {
@@ -2808,7 +2886,6 @@ var make = {
2808
2886
  }),
2809
2887
  pushBranch: (sessionId) => Effect4.gen(function* () {
2810
2888
  const worktreeDir = getWorktreeDir(sessionId);
2811
- const branchName = getBranchName(sessionId);
2812
2889
  const exists = yield* directoryExists(worktreeDir);
2813
2890
  if (!exists) {
2814
2891
  return yield* Effect4.fail(
@@ -2818,7 +2895,7 @@ var make = {
2818
2895
  })
2819
2896
  );
2820
2897
  }
2821
- yield* gitExec(`git push -u origin "${branchName}"`, worktreeDir).pipe(
2898
+ yield* gitExec("git push -u origin HEAD", worktreeDir).pipe(
2822
2899
  Effect4.mapError(
2823
2900
  (error) => new GitError({
2824
2901
  message: `Failed to push branch: ${error.message}`,
@@ -2828,7 +2905,7 @@ var make = {
2828
2905
  )
2829
2906
  );
2830
2907
  }),
2831
- createPR: (sessionId, title, body) => Effect4.gen(function* () {
2908
+ createPR: (sessionId, title, body, baseBranch) => Effect4.gen(function* () {
2832
2909
  const worktreeDir = getWorktreeDir(sessionId);
2833
2910
  const exists = yield* directoryExists(worktreeDir);
2834
2911
  if (!exists) {
@@ -2841,8 +2918,9 @@ var make = {
2841
2918
  }
2842
2919
  const escapedTitle = title.replace(/"/g, '\\"');
2843
2920
  const escapedBody = body.replace(/"/g, '\\"');
2921
+ const baseFlag = baseBranch ? ` --base "${baseBranch}"` : "";
2844
2922
  const prUrl = yield* gitExec(
2845
- `gh pr create --title "${escapedTitle}" --body "${escapedBody}"`,
2923
+ `gh pr create --title "${escapedTitle}" --body "${escapedBody}"${baseFlag}`,
2846
2924
  worktreeDir
2847
2925
  ).pipe(
2848
2926
  Effect4.mapError(
@@ -2855,10 +2933,18 @@ var make = {
2855
2933
  );
2856
2934
  return prUrl;
2857
2935
  }),
2936
+ getCurrentBranch: () => gitExec("git branch --show-current").pipe(
2937
+ Effect4.mapError(
2938
+ (error) => new GitError({
2939
+ message: `Failed to get current branch: ${error.message}`,
2940
+ operation: "getCurrentBranch",
2941
+ cause: error
2942
+ })
2943
+ )
2944
+ ),
2858
2945
  renameBranch: (sessionId, displayName) => Effect4.gen(function* () {
2859
2946
  const worktreeDir = getWorktreeDir(sessionId);
2860
2947
  const oldBranchName = getBranchName(sessionId);
2861
- const newBranchName = `${BRANCH_PREFIX}/${displayName}`;
2862
2948
  const exists = yield* directoryExists(worktreeDir);
2863
2949
  if (!exists) {
2864
2950
  return yield* Effect4.fail(
@@ -2868,6 +2954,8 @@ var make = {
2868
2954
  })
2869
2955
  );
2870
2956
  }
2957
+ const desiredName = `${BRANCH_PREFIX}/${displayName}`;
2958
+ const newBranchName = yield* findAvailableBranchName(desiredName);
2871
2959
  yield* gitExec(
2872
2960
  `git branch -m "${oldBranchName}" "${newBranchName}"`,
2873
2961
  worktreeDir
@@ -2963,7 +3051,7 @@ function createMemoryGitService(stateRef, commitCounterRef) {
2963
3051
  );
2964
3052
  }
2965
3053
  }),
2966
- createPR: (sessionId, title, _body) => Effect5.gen(function* () {
3054
+ createPR: (sessionId, title, _body, _baseBranch) => Effect5.gen(function* () {
2967
3055
  const state = yield* Ref3.get(stateRef);
2968
3056
  const worktree = state.get(sessionId);
2969
3057
  if (!worktree) {
@@ -2977,6 +3065,8 @@ function createMemoryGitService(stateRef, commitCounterRef) {
2977
3065
  const slug = title.toLowerCase().replace(/\s+/g, "-").slice(0, 30);
2978
3066
  return `https://github.com/test/repo/pull/${slug}`;
2979
3067
  }),
3068
+ getCurrentBranch: () => Effect5.succeed("main"),
3069
+ // Default to main for tests
2980
3070
  renameBranch: (sessionId, displayName) => Effect5.gen(function* () {
2981
3071
  const state = yield* Ref3.get(stateRef);
2982
3072
  const worktree = state.get(sessionId);
@@ -3018,7 +3108,7 @@ var MemoryGit = {
3018
3108
 
3019
3109
  // src/layers/guardrails/file-system.ts
3020
3110
  init_esm_shims();
3021
- import { mkdir as mkdir2, readFile, writeFile } from "fs/promises";
3111
+ import { mkdir as mkdir2, readFile as readFile2, writeFile } from "fs/promises";
3022
3112
  import { join as join2 } from "path";
3023
3113
  import { DateTime, Effect as Effect6, Layer as Layer3 } from "effect";
3024
3114
 
@@ -3200,7 +3290,9 @@ var LoopSummarySchema = S4.Struct({
3200
3290
  success: S4.Boolean,
3201
3291
  sessionId: S4.String,
3202
3292
  completedTasks: S4.Array(S4.String),
3203
- durationMs: S4.Number
3293
+ durationMs: S4.Number,
3294
+ branchPushed: S4.optional(S4.Boolean),
3295
+ prUrl: S4.optional(S4.String)
3204
3296
  });
3205
3297
  var LoopErrorSchema = S4.Struct({
3206
3298
  message: S4.String,
@@ -3457,6 +3549,17 @@ var WorktreeRemovedEventSchema = taggedEvent("WorktreeRemoved", {
3457
3549
  sessionId: S7.String,
3458
3550
  timestamp: S7.Number
3459
3551
  });
3552
+ var BranchPushedEventSchema = taggedEvent("BranchPushed", {
3553
+ sessionId: S7.String,
3554
+ branchName: S7.String,
3555
+ timestamp: S7.Number
3556
+ });
3557
+ var PRCreatedEventSchema = taggedEvent("PRCreated", {
3558
+ sessionId: S7.String,
3559
+ prUrl: S7.String,
3560
+ title: S7.String,
3561
+ timestamp: S7.Number
3562
+ });
3460
3563
  var SessionNameGeneratedEventSchema = taggedEvent(
3461
3564
  "SessionNameGenerated",
3462
3565
  {
@@ -3498,6 +3601,8 @@ var DomainEventSchema = S7.Union(
3498
3601
  ProgressUpdatedEventSchema,
3499
3602
  WorktreeCreatedEventSchema,
3500
3603
  WorktreeRemovedEventSchema,
3604
+ BranchPushedEventSchema,
3605
+ PRCreatedEventSchema,
3501
3606
  SessionNameGeneratedEventSchema
3502
3607
  );
3503
3608
  var DomainEventUtils = {
@@ -3641,7 +3746,9 @@ var SessionSchema = S13.Struct({
3641
3746
  worktreePath: S13.optional(S13.String),
3642
3747
  branchName: S13.optional(S13.String),
3643
3748
  /** Task-based descriptive name (kebab-case slug, e.g., "add-dark-mode-toggle") */
3644
- displayName: S13.optional(S13.String)
3749
+ displayName: S13.optional(S13.String),
3750
+ /** The branch ferix was started from - used as PR base branch */
3751
+ baseBranch: S13.optional(S13.String)
3645
3752
  });
3646
3753
  var decodeSession = S13.decodeUnknown(SessionSchema);
3647
3754
 
@@ -4069,7 +4176,7 @@ var make2 = {
4069
4176
  const existing = yield* Effect6.tryPromise({
4070
4177
  try: async () => {
4071
4178
  try {
4072
- const content = await readFile(guardrailsPath, "utf-8");
4179
+ const content = await readFile2(guardrailsPath, "utf-8");
4073
4180
  return content;
4074
4181
  } catch {
4075
4182
  return null;
@@ -4118,7 +4225,7 @@ var make2 = {
4118
4225
  const content = yield* Effect6.tryPromise({
4119
4226
  try: async () => {
4120
4227
  try {
4121
- return await readFile(guardrailsPath, "utf-8");
4228
+ return await readFile2(guardrailsPath, "utf-8");
4122
4229
  } catch {
4123
4230
  return null;
4124
4231
  }
@@ -4673,7 +4780,7 @@ function createProviderLayer2(name) {
4673
4780
 
4674
4781
  // src/layers/plan/file-system.ts
4675
4782
  init_esm_shims();
4676
- import { access as access2, mkdir as mkdir3, readdir, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
4783
+ import { access as access2, mkdir as mkdir3, readdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
4677
4784
  import { join as join3 } from "path";
4678
4785
  import { Effect as Effect12, Layer as Layer7 } from "effect";
4679
4786
 
@@ -4767,7 +4874,7 @@ var make3 = {
4767
4874
  if (sessionId) {
4768
4875
  const planPath = getPlanPath(sessionId, planId);
4769
4876
  const content = yield* Effect12.tryPromise({
4770
- try: () => readFile2(planPath, "utf-8"),
4877
+ try: () => readFile3(planPath, "utf-8"),
4771
4878
  catch: (error) => new PlanStoreError({
4772
4879
  message: `Failed to read plan file: ${planPath}`,
4773
4880
  operation: "load",
@@ -4802,7 +4909,7 @@ var make3 = {
4802
4909
  }).pipe(Effect12.orElseSucceed(() => false));
4803
4910
  if (exists) {
4804
4911
  const content = yield* Effect12.tryPromise({
4805
- try: () => readFile2(planPath, "utf-8"),
4912
+ try: () => readFile3(planPath, "utf-8"),
4806
4913
  catch: (error) => new PlanStoreError({
4807
4914
  message: `Failed to read plan file: ${planPath}`,
4808
4915
  operation: "load",
@@ -4943,7 +5050,7 @@ var MemoryPlan = {
4943
5050
 
4944
5051
  // src/layers/progress/file-system.ts
4945
5052
  init_esm_shims();
4946
- import { mkdir as mkdir4, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
5053
+ import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile3 } from "fs/promises";
4947
5054
  import { join as join4 } from "path";
4948
5055
  import { DateTime as DateTime3, Effect as Effect14, Layer as Layer9 } from "effect";
4949
5056
 
@@ -5011,7 +5118,7 @@ var make4 = {
5011
5118
  const existing = yield* Effect14.tryPromise({
5012
5119
  try: async () => {
5013
5120
  try {
5014
- const content = await readFile3(progressPath, "utf-8");
5121
+ const content = await readFile4(progressPath, "utf-8");
5015
5122
  return content;
5016
5123
  } catch {
5017
5124
  return null;
@@ -5056,7 +5163,7 @@ var make4 = {
5056
5163
  const content = yield* Effect14.tryPromise({
5057
5164
  try: async () => {
5058
5165
  try {
5059
- return await readFile3(progressPath, "utf-8");
5166
+ return await readFile4(progressPath, "utf-8");
5060
5167
  } catch {
5061
5168
  return null;
5062
5169
  }
@@ -5147,7 +5254,7 @@ var MemoryProgress = {
5147
5254
 
5148
5255
  // src/layers/session/file-system.ts
5149
5256
  init_esm_shims();
5150
- import { mkdir as mkdir5, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
5257
+ import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
5151
5258
  import { join as join5 } from "path";
5152
5259
  import { DateTime as DateTime5, Effect as Effect16, Layer as Layer11 } from "effect";
5153
5260
  import { humanId } from "human-id";
@@ -5230,7 +5337,7 @@ var make5 = {
5230
5337
  get: (sessionId) => Effect16.gen(function* () {
5231
5338
  const sessionPath = getSessionPath(sessionId);
5232
5339
  const content = yield* Effect16.tryPromise({
5233
- try: () => readFile4(sessionPath, "utf-8"),
5340
+ try: () => readFile5(sessionPath, "utf-8"),
5234
5341
  catch: (error) => new SessionStoreError({
5235
5342
  message: `Failed to read session file: ${sessionPath}`,
5236
5343
  operation: "get",
@@ -5949,7 +6056,7 @@ import { DateTime as DateTime8, Effect as Effect21, pipe, Ref as Ref10, Stream a
5949
6056
 
5950
6057
  // src/layers/plan/task-generation.ts
5951
6058
  init_esm_shims();
5952
- import { mkdir as mkdir6, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
6059
+ import { mkdir as mkdir6, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
5953
6060
  import { join as join6 } from "path";
5954
6061
  import { Effect as Effect19 } from "effect";
5955
6062
  var PLANS_DIR4 = ".ferix/plans";
@@ -6177,6 +6284,15 @@ init_esm_shims();
6177
6284
 
6178
6285
  // src/orchestrator/plan-updates/helpers.ts
6179
6286
  init_esm_shims();
6287
+ var VERIFICATION_PATTERNS = [
6288
+ /\b(lint|linting|format|formatting)\b/i,
6289
+ /\b(run\s+tests?|testing)\b/i,
6290
+ /\b(verify|verification|validate|validation)\b/i,
6291
+ /^run\s+(bun|npm|yarn|pnpm)\s+(lint|test|format|build)/i
6292
+ ];
6293
+ function isVerificationTask(title) {
6294
+ return VERIFICATION_PATTERNS.some((pattern) => pattern.test(title));
6295
+ }
6180
6296
  function createPlanFromTasks(sessionId, originalTask, tasks, createdAt) {
6181
6297
  return {
6182
6298
  id: PlanId(`${sessionId}-plan`),
@@ -6446,16 +6562,24 @@ planUpdateRegistry.register({
6446
6562
  init_esm_shims();
6447
6563
  planUpdateRegistry.register({
6448
6564
  tag: "TasksDefined",
6449
- handle: (signal, _currentPlan, context) => ({
6450
- plan: createPlanFromTasks(
6451
- context.sessionId,
6452
- context.originalTask,
6453
- signal.tasks,
6454
- context.timestamp
6455
- ),
6456
- operation: "create",
6457
- eventTag: "PlanCreated"
6458
- })
6565
+ handle: (signal, _currentPlan, context) => {
6566
+ const filteredTasks = signal.tasks.filter(
6567
+ (task) => !isVerificationTask(task.title)
6568
+ );
6569
+ if (filteredTasks.length === 0) {
6570
+ return void 0;
6571
+ }
6572
+ return {
6573
+ plan: createPlanFromTasks(
6574
+ context.sessionId,
6575
+ context.originalTask,
6576
+ filteredTasks,
6577
+ context.timestamp
6578
+ ),
6579
+ operation: "create",
6580
+ eventTag: "PlanCreated"
6581
+ };
6582
+ }
6459
6583
  });
6460
6584
 
6461
6585
  // src/orchestrator/plan-updates/index.ts
@@ -6677,7 +6801,12 @@ function buildVerifyPrompt(verifyCommands, prompts) {
6677
6801
  Run these verification commands:
6678
6802
  ${verifyCommands.map((cmd) => `- ${cmd}`).join("\n")}
6679
6803
 
6680
- If any fail, fix the issues and re-verify.`;
6804
+ If any fail, fix the issues and re-verify.
6805
+
6806
+ IMPORTANT: Once ALL verification commands pass:
6807
+ - Emit <ferix:task-complete id="N"> with a summary of what was done
6808
+ - If this was the last task, also emit <ferix:complete>
6809
+ - Do NOT run verification again after it passes`;
6681
6810
  return prompts?.phases?.verify ?? defaultVerifyPrompt;
6682
6811
  }
6683
6812
  var TASK_STATUS_ICONS = {
@@ -6797,8 +6926,13 @@ ${config.task}`);
6797
6926
  sections.push(getPhasePrompt("planning", prompts, DEFAULT_PLANNING_PROMPT));
6798
6927
  sections.push(getPhasePrompt("execution", prompts, DEFAULT_EXECUTION_PROMPT));
6799
6928
  sections.push(getPhasePrompt("check", prompts, DEFAULT_CHECK_PROMPT));
6800
- if (config.verifyCommands.length > 0) {
6801
- sections.push(buildVerifyPrompt(config.verifyCommands, prompts));
6929
+ if (config.verifyCommands.length > 0 && plan && !areAllTasksComplete(plan)) {
6930
+ const currentTask = plan.tasks.find(
6931
+ (t) => t.status === "in_progress" || t.status === "pending"
6932
+ );
6933
+ if (currentTask) {
6934
+ sections.push(buildVerifyPrompt(config.verifyCommands, prompts));
6935
+ }
6802
6936
  }
6803
6937
  sections.push(getPhasePrompt("review", prompts, DEFAULT_REVIEW_PROMPT));
6804
6938
  sections.push(
@@ -6811,6 +6945,12 @@ Iteration ${iteration} of ${config.maxIterations || "unlimited"}
6811
6945
  Begin.`);
6812
6946
  return sections.join("\n\n");
6813
6947
  }
6948
+ function areAllTasksComplete(plan) {
6949
+ if (!plan || plan.tasks.length === 0) {
6950
+ return false;
6951
+ }
6952
+ return plan.tasks.every((t) => t.status === "done" || t.status === "skipped");
6953
+ }
6814
6954
 
6815
6955
  // src/orchestrator/discovery.ts
6816
6956
  function processTextSignals(signalParser, text, context) {
@@ -7124,6 +7264,28 @@ function createIterationStream(llm, signalParser, planStore, currentPlanRef, loo
7124
7264
  events.push(...planEvents);
7125
7265
  }
7126
7266
  if (result.completed) {
7267
+ yield* Effect22.logInfo(
7268
+ "[DEBUG] createIterationStream: LLM emitted completion signal"
7269
+ );
7270
+ yield* Ref11.set(loopCompletedRef, true);
7271
+ }
7272
+ const updatedPlan = yield* Ref11.get(currentPlanRef);
7273
+ const allComplete = areAllTasksComplete(updatedPlan);
7274
+ yield* Effect22.logInfo(
7275
+ "[DEBUG] createIterationStream: Auto-complete check",
7276
+ {
7277
+ llmEmittedComplete: result.completed,
7278
+ allTasksComplete: allComplete,
7279
+ taskStatuses: updatedPlan?.tasks.map((t) => ({
7280
+ id: t.id,
7281
+ status: t.status
7282
+ }))
7283
+ }
7284
+ );
7285
+ if (allComplete) {
7286
+ yield* Effect22.logInfo(
7287
+ "[DEBUG] createIterationStream: All tasks complete - ending loop"
7288
+ );
7127
7289
  yield* Ref11.set(loopCompletedRef, true);
7128
7290
  }
7129
7291
  return Stream8.fromIterable(events);
@@ -7183,6 +7345,14 @@ function runLoop(config) {
7183
7345
  })
7184
7346
  )
7185
7347
  );
7348
+ const baseBranch = yield* git.getCurrentBranch().pipe(
7349
+ Effect23.tapError(
7350
+ (error) => Effect23.logDebug("Failed to get current branch", {
7351
+ error: String(error)
7352
+ })
7353
+ ),
7354
+ Effect23.orElseSucceed(() => void 0)
7355
+ );
7186
7356
  const worktreePath = yield* git.createWorktree(session.id).pipe(
7187
7357
  Effect23.mapError(
7188
7358
  (e) => new OrchestratorError({
@@ -7196,7 +7366,8 @@ function runLoop(config) {
7196
7366
  yield* sessionStore.update(session.id, {
7197
7367
  ...session,
7198
7368
  worktreePath,
7199
- branchName
7369
+ branchName,
7370
+ baseBranch
7200
7371
  }).pipe(
7201
7372
  Effect23.tapError(
7202
7373
  (error) => Effect23.logDebug("Failed to update session with worktree info", {
@@ -7216,7 +7387,8 @@ function runLoop(config) {
7216
7387
  };
7217
7388
  const loopCompletedRef = yield* Ref12.make(false);
7218
7389
  const currentPlanRef = yield* Ref12.make(void 0);
7219
- const sessionRef = yield* Ref12.make(session);
7390
+ const initialSession = { ...session, baseBranch };
7391
+ const sessionRef = yield* Ref12.make(initialSession);
7220
7392
  const maxIterations = config.maxIterations === 0 ? Number.POSITIVE_INFINITY : config.maxIterations;
7221
7393
  const loopStarted = {
7222
7394
  _tag: "LoopStarted",
@@ -7273,8 +7445,14 @@ function runLoop(config) {
7273
7445
  );
7274
7446
  const completionStream = createCompletionStream(
7275
7447
  sessionStore,
7276
- git,
7277
- session,
7448
+ {
7449
+ commitChanges: git.commitChanges,
7450
+ removeWorktreeKeepBranch: git.removeWorktreeKeepBranch,
7451
+ pushBranch: git.pushBranch,
7452
+ createPR: git.createPR,
7453
+ getBranchName: git.getBranchName
7454
+ },
7455
+ sessionRef,
7278
7456
  config,
7279
7457
  startTime,
7280
7458
  loopCompletedRef,
@@ -7303,9 +7481,21 @@ function runLoop(config) {
7303
7481
  )
7304
7482
  );
7305
7483
  }
7306
- function createCompletionStream(sessionStore, git, session, config, startTime, loopCompletedRef, _worktreePath) {
7484
+ function buildPRBody(session, config) {
7485
+ const completedTasks = session.completedTasks.length > 0 ? session.completedTasks.map((t) => `- ${t}`).join("\n") : "- No specific tasks tracked";
7486
+ return `## Summary
7487
+ ${config.task}
7488
+
7489
+ ## Completed Tasks
7490
+ ${completedTasks}
7491
+
7492
+ ---
7493
+ Generated by Ferix`;
7494
+ }
7495
+ function createCompletionStream(sessionStore, git, sessionRef, config, startTime, loopCompletedRef, _worktreePath) {
7307
7496
  return Stream9.unwrap(
7308
7497
  Effect23.gen(function* () {
7498
+ const session = yield* Ref12.get(sessionRef);
7309
7499
  const endTimeUtc = yield* DateTime10.now;
7310
7500
  const endTime = DateTime10.toEpochMillis(endTimeUtc);
7311
7501
  const durationMs = endTime - startTime;
@@ -7319,6 +7509,36 @@ function createCompletionStream(sessionStore, git, session, config, startTime, l
7319
7509
  ),
7320
7510
  Effect23.orElseSucceed(() => void 0)
7321
7511
  );
7512
+ let branchPushed = false;
7513
+ if (config.push === true) {
7514
+ const pushResult = yield* git.pushBranch(session.id).pipe(
7515
+ Effect23.map(() => true),
7516
+ Effect23.tapError(
7517
+ (error) => Effect23.logDebug("Push failed, continuing", {
7518
+ sessionId: session.id,
7519
+ error: String(error)
7520
+ })
7521
+ ),
7522
+ Effect23.orElseSucceed(() => false)
7523
+ );
7524
+ branchPushed = pushResult;
7525
+ }
7526
+ let prUrl;
7527
+ if (config.pr === true && branchPushed) {
7528
+ const title = `feat: ${session.originalTask.slice(0, 50)}`;
7529
+ const body = buildPRBody(session, config);
7530
+ const prResult = yield* git.createPR(session.id, title, body, session.baseBranch).pipe(
7531
+ Effect23.map((url) => url),
7532
+ Effect23.tapError(
7533
+ (error) => Effect23.logDebug("PR creation failed, continuing", {
7534
+ sessionId: session.id,
7535
+ error: String(error)
7536
+ })
7537
+ ),
7538
+ Effect23.orElseSucceed(() => void 0)
7539
+ );
7540
+ prUrl = prResult;
7541
+ }
7322
7542
  yield* git.removeWorktreeKeepBranch(session.id).pipe(
7323
7543
  Effect23.tapError(
7324
7544
  (error) => Effect23.logDebug("Worktree cleanup failed, continuing", {
@@ -7338,7 +7558,9 @@ function createCompletionStream(sessionStore, git, session, config, startTime, l
7338
7558
  success: completed,
7339
7559
  sessionId: session.id,
7340
7560
  completedTasks: session.completedTasks,
7341
- durationMs
7561
+ durationMs,
7562
+ branchPushed: branchPushed || void 0,
7563
+ prUrl: prUrl || void 0
7342
7564
  };
7343
7565
  yield* sessionStore.update(session.id, {
7344
7566
  ...session,
@@ -7353,11 +7575,26 @@ function createCompletionStream(sessionStore, git, session, config, startTime, l
7353
7575
  ),
7354
7576
  Effect23.orElseSucceed(() => void 0)
7355
7577
  );
7356
- const loopCompleted = { _tag: "LoopCompleted", summary };
7357
- return pipe3(
7358
- Stream9.succeed(worktreeRemoved),
7359
- Stream9.concat(Stream9.succeed(loopCompleted))
7360
- );
7578
+ const events = [worktreeRemoved];
7579
+ if (branchPushed) {
7580
+ events.push({
7581
+ _tag: "BranchPushed",
7582
+ sessionId: session.id,
7583
+ branchName: session.branchName ?? git.getBranchName(session.id),
7584
+ timestamp: endTime
7585
+ });
7586
+ }
7587
+ if (prUrl) {
7588
+ events.push({
7589
+ _tag: "PRCreated",
7590
+ sessionId: session.id,
7591
+ prUrl,
7592
+ title: `feat: ${session.originalTask.slice(0, 50)}`,
7593
+ timestamp: endTime
7594
+ });
7595
+ }
7596
+ events.push({ _tag: "LoopCompleted", summary });
7597
+ return Stream9.fromIterable(events);
7361
7598
  })
7362
7599
  );
7363
7600
  }
@@ -7398,7 +7635,8 @@ init_esm_shims();
7398
7635
 
7399
7636
  // src/index.ts
7400
7637
  var program = new Command();
7401
- program.name("ferix-code").description("Composable RALPH loops for AI coding agents").version(package_default.version, "-v, --version", "Output the version number").argument("<task>", "Task description or path to PRD file").option("-i, --iterations <n>", "Maximum iterations", "1").option("-c, --verify <commands...>", "Verification commands to run").option("--branch <name>", "Git branch to create").option("--push", "Push branch after completion").option("--pr", "Create PR after pushing").option("--provider <name>", "LLM provider to use (claude, cursor)", "claude").action(async (task, options) => {
7638
+ program.name("ferix-code").description("Composable RALPH loops for AI coding agents").version(package_default.version, "-v, --version", "Output the version number");
7639
+ program.command("run", { isDefault: true }).argument("<task>", "Task description or path to PRD file").option("-i, --iterations <n>", "Maximum iterations", "1").option("-c, --verify <commands...>", "Verification commands to run").option("--branch <name>", "Git branch to create").option("--push", "Push branch after completion").option("--pr", "Create PR after pushing").option("--provider <name>", "LLM provider to use (claude, cursor)", "claude").action(async (task, options) => {
7402
7640
  const config = {
7403
7641
  task,
7404
7642
  maxIterations: Number.parseInt(options.iterations, 10),
@@ -7415,11 +7653,58 @@ program.name("ferix-code").description("Composable RALPH loops for AI coding age
7415
7653
  process.exit(1);
7416
7654
  }
7417
7655
  });
7656
+ program.command("sync").description("Discover and install skills based on your dependencies").option("-p, --path <path>", "Path to package.json", "./package.json").option("-d, --dry-run", "List skills without installing").option("-g, --global", "Install globally instead of project-level").action(async (options) => {
7657
+ try {
7658
+ console.log("\nScanning package.json...");
7659
+ const result = await Effect25.runPromise(
7660
+ sync(options.path, {
7661
+ dryRun: options.dryRun ?? false,
7662
+ global: options.global ?? false
7663
+ })
7664
+ );
7665
+ console.log(
7666
+ `Found ${pc17.bold(String(result.dependencies.length))} dependencies`
7667
+ );
7668
+ console.log(
7669
+ `Resolved ${pc17.bold(String(result.orgs.length))} unique GitHub organizations`
7670
+ );
7671
+ if (result.skillRepos.length === 0) {
7672
+ console.log(
7673
+ `
7674
+ ${pc17.yellow("No skill repositories found for your dependencies.")}`
7675
+ );
7676
+ return;
7677
+ }
7678
+ console.log(
7679
+ `
7680
+ Found ${pc17.bold(String(result.skillRepos.length))} skill repositories:
7681
+ `
7682
+ );
7683
+ for (const repo of result.skillRepos) {
7684
+ console.log(` ${pc17.green("\u2022")} ${repo.owner}/${repo.repo}`);
7685
+ }
7686
+ if (options.dryRun) {
7687
+ console.log(
7688
+ `
7689
+ ${pc17.dim("Run without --dry-run to install these skills.")}`
7690
+ );
7691
+ } else {
7692
+ console.log(
7693
+ `
7694
+ ${pc17.green("\u2713")} Installed ${pc17.bold(String(result.installed.length))} skill repositories`
7695
+ );
7696
+ }
7697
+ } catch (error) {
7698
+ console.error(pc17.red("Error:"), error);
7699
+ process.exit(1);
7700
+ }
7701
+ });
7418
7702
  program.parse();
7419
7703
  export {
7420
7704
  AnyToolInputSchema,
7421
7705
  AssistantMessageSchema,
7422
7706
  BashToolInputSchema,
7707
+ BranchPushedEventSchema,
7423
7708
  CheckFailedEventSchema,
7424
7709
  CheckFailedSignalSchema,
7425
7710
  CheckPassedEventSchema,
@@ -7502,6 +7787,7 @@ export {
7502
7787
  MemoryPlan,
7503
7788
  MemoryProgress,
7504
7789
  MemorySession,
7790
+ MetricsError,
7505
7791
  Mock,
7506
7792
  Mock as MockLLM,
7507
7793
  OpenCodeCliEventSchema,
@@ -7515,6 +7801,7 @@ export {
7515
7801
  OpenCodeToolStateSchema,
7516
7802
  OpenCodeToolUseEventSchema,
7517
7803
  OrchestratorError,
7804
+ PRCreatedEventSchema,
7518
7805
  PROVIDER_CONFIGS,
7519
7806
  ParseError,
7520
7807
  PhaseBasicInfoSchema,
@@ -7550,6 +7837,7 @@ export {
7550
7837
  PromptConfigSchema,
7551
7838
  ProviderNameSchema,
7552
7839
  ReadToolInputSchema,
7840
+ RetryExhaustedError,
7553
7841
  ReviewCompleteDataSchema,
7554
7842
  ReviewCompleteEventSchema,
7555
7843
  ReviewCompleteSignalSchema,
@@ -7585,6 +7873,7 @@ export {
7585
7873
  TextContentBlockSchema,
7586
7874
  TextDeltaSchema,
7587
7875
  TextEventSchema,
7876
+ TokenBudgetError,
7588
7877
  ToolEndEventSchema,
7589
7878
  ToolInputSchemaRegistry,
7590
7879
  ToolStartEventSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ferix-code",
3
- "version": "0.0.2-beta.18",
3
+ "version": "0.0.2-beta.20",
4
4
  "description": "Composable RALPH loops for AI coding agents - v2 with Effect",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,6 +19,7 @@
19
19
  "bump": "npm version prerelease --preid=beta --workspaces=false && bun run build && bun publish --tag beta"
20
20
  },
21
21
  "dependencies": {
22
+ "@ferix/sync": "*",
22
23
  "commander": "^14.0.0",
23
24
  "effect": "^3.19.15",
24
25
  "human-id": "^4.1.3",