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 +97 -7
- package/dist/index.js +336 -47
- package/package.json +2 -1
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.
|
|
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 {
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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: () =>
|
|
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: () =>
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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: () =>
|
|
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
|
|
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
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
7277
|
-
|
|
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
|
|
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
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
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")
|
|
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.
|
|
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",
|