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