lalph 0.2.20 → 0.3.0

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/src/Presets.ts ADDED
@@ -0,0 +1,165 @@
1
+ import { Array, Effect, Option, Schema } from "effect"
2
+ import { Setting, Settings } from "./Settings.ts"
3
+ import { CliAgentPreset, CliAgentPresetId } from "./domain/CliAgentPreset.ts"
4
+ import { Prompt } from "effect/unstable/cli"
5
+ import { allCliAgents, type AnyCliAgent } from "./domain/CliAgent.ts"
6
+ import { parseCommand } from "./shared/child-process.ts"
7
+ import { IssueSource } from "./IssueSource.ts"
8
+
9
+ export const allCliAgentPresets = new Setting(
10
+ "cliAgentPresets",
11
+ Schema.Array(CliAgentPreset),
12
+ )
13
+
14
+ export const getAllCliAgentPresets = Settings.get(allCliAgentPresets).pipe(
15
+ Effect.map(Option.getOrElse((): ReadonlyArray<CliAgentPreset> => [])),
16
+ )
17
+
18
+ export const getPresetsWithMetadata = <S extends Schema.Top>(
19
+ source: string,
20
+ schema: S,
21
+ ) =>
22
+ getAllCliAgentPresets.pipe(
23
+ Effect.flatMap(
24
+ Effect.forEach((preset) =>
25
+ preset.decodeMetadata(source, schema).pipe(
26
+ Effect.map(
27
+ Option.map((metadata) => ({
28
+ preset,
29
+ metadata,
30
+ })),
31
+ ),
32
+ ),
33
+ ),
34
+ ),
35
+ Effect.map(Array.getSomes),
36
+ )
37
+
38
+ export const cliAgentPresetById = Effect.fnUntraced(function* (
39
+ presetId: CliAgentPresetId,
40
+ ) {
41
+ const presets = yield* getAllCliAgentPresets
42
+ return Array.findFirst(presets, (p) => p.id === presetId)
43
+ })
44
+
45
+ export const getDefaultCliAgentPreset = Effect.gen(function* () {
46
+ const presets = yield* getAllCliAgentPresets
47
+ const preset = presets.find((p) => p.id === CliAgentPreset.defaultId)
48
+ return preset ?? (yield* welcomeWizard)
49
+ })
50
+
51
+ export const welcomeWizard = Effect.gen(function* () {
52
+ const welcome = [
53
+ " .--.",
54
+ " |^()^| lalph",
55
+ " '--'",
56
+ "",
57
+ "Let's setup your default AI agent preset.",
58
+ "AI agent presets let you configure what cli agent lalph",
59
+ "uses to run tasks.",
60
+ "",
61
+ ].join("\n")
62
+ console.log(welcome)
63
+ return yield* addOrUpdatePreset({
64
+ idOverride: CliAgentPreset.defaultId,
65
+ })
66
+ })
67
+
68
+ export const selectCliAgentPreset = Effect.gen(function* () {
69
+ const presets = yield* getAllCliAgentPresets
70
+ if (presets.length === 0) {
71
+ return yield* welcomeWizard
72
+ } else if (presets.length === 1) {
73
+ const preset = presets[0]!
74
+ yield* Effect.log(`Using agent preset: ${preset.id}`)
75
+ return preset
76
+ }
77
+ const selection = yield* Prompt.autoComplete({
78
+ message: "Select a preset:",
79
+ choices: presets.map((p) => ({
80
+ title: p.id,
81
+ value: p,
82
+ })),
83
+ })
84
+ return selection!
85
+ })
86
+
87
+ export const addOrUpdatePreset = Effect.fnUntraced(function* (options?: {
88
+ readonly existing?: CliAgentPreset
89
+ readonly idOverride?: CliAgentPresetId
90
+ }) {
91
+ const presets = yield* getAllCliAgentPresets
92
+
93
+ const id = options?.existing
94
+ ? options.existing.id
95
+ : (options?.idOverride ??
96
+ CliAgentPresetId.makeUnsafe(
97
+ yield* Prompt.text({
98
+ message: "Preset name",
99
+ validate(input) {
100
+ input = input.trim()
101
+ if (input.length === 0) {
102
+ return Effect.fail("Preset name cannot be empty")
103
+ } else if (presets.some((p) => p.id === input)) {
104
+ return Effect.fail("Preset already exists")
105
+ }
106
+ return Effect.succeed(input)
107
+ },
108
+ }),
109
+ ))
110
+
111
+ const cliAgent = yield* selectCliAgent(options?.existing?.cliAgent.id)
112
+ const extraArgs = yield* Prompt.text({
113
+ message: "Extra arguments? (leave empty for none)",
114
+ default: options?.existing?.extraArgs.join(" ") ?? "",
115
+ })
116
+ .asEffect()
117
+ .pipe(Effect.map(parseCommand))
118
+ const commandPrefix = yield* promptForCommandPrefix(
119
+ options?.existing?.commandPrefix,
120
+ )
121
+
122
+ let preset = new CliAgentPreset({
123
+ id,
124
+ cliAgent,
125
+ commandPrefix,
126
+ extraArgs,
127
+ sourceMetadata: {},
128
+ })
129
+
130
+ if (id !== CliAgentPreset.defaultId) {
131
+ const source = yield* IssueSource
132
+ preset = yield* source.updateCliAgentPreset(preset)
133
+ }
134
+
135
+ yield* Settings.set(
136
+ allCliAgentPresets,
137
+ Option.some(
138
+ options?.existing
139
+ ? presets.map((p) => (p.id === preset.id ? preset : p))
140
+ : [...presets, preset],
141
+ ),
142
+ )
143
+
144
+ return preset
145
+ })
146
+
147
+ const selectCliAgent = (initial?: AnyCliAgent["id"]) =>
148
+ Prompt.select({
149
+ message: "Select the CLI agent to use",
150
+ choices: allCliAgents.map((agent) => ({
151
+ title: agent.name,
152
+ value: agent,
153
+ selected: agent.id === initial,
154
+ })),
155
+ })
156
+
157
+ const promptForCommandPrefix = Effect.fnUntraced(function* (
158
+ initial?: ReadonlyArray<string>,
159
+ ) {
160
+ const prefix = yield* Prompt.text({
161
+ message: "Command prefix? (leave empty for none)",
162
+ default: initial ? initial.join(" ") : "",
163
+ })
164
+ return parseCommand(prefix)
165
+ })
package/src/Projects.ts CHANGED
@@ -135,7 +135,7 @@ export const welcomeWizard = Effect.gen(function* () {
135
135
  " |^()^| lalph",
136
136
  " '--'",
137
137
  "",
138
- "Welcome! Let's add your first project.",
138
+ "Let's add your first project.",
139
139
  "Projects let you configure how lalph runs tasks.",
140
140
  "",
141
141
  ].join("\n")
@@ -168,6 +168,9 @@ export const addOrUpdateProject = Effect.fnUntraced(function* (
168
168
  const targetBranch = pipe(
169
169
  yield* Prompt.text({
170
170
  message: "Target branch (leave empty to use HEAD)",
171
+ default: existing
172
+ ? Option.getOrElse(existing.targetBranch, () => "")
173
+ : "",
171
174
  }),
172
175
  String.trim,
173
176
  Option.liftPredicate(String.isNonEmpty),
@@ -179,16 +182,19 @@ export const addOrUpdateProject = Effect.fnUntraced(function* (
179
182
  title: "Pull Request",
180
183
  description: "Create a pull request for each task",
181
184
  value: "pr",
185
+ selected: existing ? existing.gitFlow === "pr" : false,
182
186
  },
183
187
  {
184
188
  title: "Commit",
185
189
  description: "Tasks are committed directly to the target branch",
186
190
  value: "commit",
191
+ selected: existing ? existing.gitFlow === "pr" : false,
187
192
  },
188
193
  ] as const,
189
194
  })
190
195
  const reviewAgent = yield* Prompt.toggle({
191
196
  message: "Enable review agent?",
197
+ initial: existing ? existing.reviewAgent : true,
192
198
  })
193
199
 
194
200
  const project = new Project({
package/src/PromptGen.ts CHANGED
@@ -156,9 +156,12 @@ ${options.task.description}
156
156
 
157
157
  # Instructions
158
158
 
159
- 1. Study the ${options.specsDirectory}/README.md file (if available), and read
160
- the entire prd.yml file to understand the context of the task and any key
161
- learnings from previous work.
159
+ Your job is to implement the task described above.
160
+
161
+ 1. Carefully study the prd.yml file to understand the context of the task, and
162
+ discover any key learnings from previous work.
163
+ Also read the ${options.specsDirectory}/README.md file (if available), to see
164
+ if any previous specifications could assist you.
162
165
  2. ${options.gitFlow.setupInstructions(options)}
163
166
  3. Implement the task.
164
167
  - If this task is a research task, **do not** make any code changes yet.
@@ -172,6 +175,7 @@ ${options.task.description}
172
175
  5. ${options.gitFlow.commitInstructions({
173
176
  githubPrInstructions: sourceMeta.githubPrInstructions,
174
177
  githubPrNumber: options.githubPrNumber,
178
+ taskId: options.task.id ?? "unknown",
175
179
  targetBranch: options.targetBranch,
176
180
  })}
177
181
  6. **After ${options.gitFlow.requiresGithubPr ? "pushing" : "committing"}**
@@ -235,9 +239,9 @@ ${prdNotes(options)}`
235
239
  const planPrompt = (options: {
236
240
  readonly plan: string
237
241
  readonly specsDirectory: string
238
- }) => `<request><![CDATA[
242
+ }) => `<request>
239
243
  ${options.plan}
240
- ]]></request>
244
+ </request>
241
245
 
242
246
  ## Instructions
243
247
 
@@ -260,7 +264,6 @@ ${options.plan}
260
264
  }
261
265
  \`\`\`
262
266
  5. Present the saved specification for review (include the full text in your response).
263
- If any corrections are needed, update the specification and adjust the plan tasks accordingly.
264
267
 
265
268
  **Important:** You are only creating or updating a plan, not implementing any tasks yet.
266
269
 
package/src/Worktree.ts CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  } from "effect"
17
17
  import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
18
18
  import { RunnerStalled } from "./domain/Errors.ts"
19
- import type { CliAgent } from "./domain/CliAgent.ts"
19
+ import type { AnyCliAgent } from "./domain/CliAgent.ts"
20
20
  import { constWorkerMaxOutputChunks, CurrentWorkerState } from "./Workers.ts"
21
21
  import { AtomRegistry } from "effect/unstable/reactivity"
22
22
  import { CurrentProjectId } from "./Settings.ts"
@@ -194,7 +194,7 @@ const makeExecHelpers = Effect.fnUntraced(function* (options: {
194
194
  provide,
195
195
  )
196
196
 
197
- const execWithOutput = (options: { readonly cliAgent: CliAgent }) =>
197
+ const execWithOutput = (options: { readonly cliAgent: AnyCliAgent }) =>
198
198
  Effect.fnUntraced(function* (command: ChildProcess.Command) {
199
199
  const handle = yield* provide(command.asEffect())
200
200
 
@@ -213,7 +213,7 @@ const makeExecHelpers = Effect.fnUntraced(function* (options: {
213
213
  return yield* handle.exitCode
214
214
  }, Effect.scoped)
215
215
 
216
- const execWithWorkerOutput = (options: { readonly cliAgent: CliAgent }) =>
216
+ const execWithWorkerOutput = (options: { readonly cliAgent: AnyCliAgent }) =>
217
217
  Effect.fnUntraced(function* (command: ChildProcess.Command) {
218
218
  const registry = yield* AtomRegistry.AtomRegistry
219
219
  const worker = yield* CurrentWorkerState
@@ -244,7 +244,7 @@ const makeExecHelpers = Effect.fnUntraced(function* (options: {
244
244
 
245
245
  const execWithStallTimeout = (options: {
246
246
  readonly stallTimeout: Duration.Duration
247
- readonly cliAgent: CliAgent
247
+ readonly cliAgent: AnyCliAgent
248
248
  }) =>
249
249
  Effect.fnUntraced(function* (command: ChildProcess.Command) {
250
250
  const registry = yield* AtomRegistry.AtomRegistry
package/src/cli.ts CHANGED
@@ -9,7 +9,6 @@ import { commandPlan } from "./commands/plan.ts"
9
9
  import { commandIssue, commandIssueAlias } from "./commands/issue.ts"
10
10
  import { commandEdit, commandEditAlias } from "./commands/edit.ts"
11
11
  import { commandSource } from "./commands/source.ts"
12
- import { commandAgent } from "./commands/agent.ts"
13
12
  import PackageJson from "../package.json" with { type: "json" }
14
13
  import { TracingLayer } from "./Tracing.ts"
15
14
  import { MinimumLogLevel } from "effect/References"
@@ -17,6 +16,7 @@ import { atomRuntime, lalphMemoMap } from "./shared/runtime.ts"
17
16
  import { PlatformServices } from "./shared/platform.ts"
18
17
  import { commandProjects, commandProjectsAlias } from "./commands/projects.ts"
19
18
  import { commandSh } from "./commands/sh.ts"
19
+ import { commandAgents, commandAgentsAlias } from "./commands/agents.ts"
20
20
 
21
21
  commandRoot.pipe(
22
22
  Command.withSubcommands([
@@ -25,10 +25,11 @@ commandRoot.pipe(
25
25
  commandEdit,
26
26
  commandSh,
27
27
  commandSource,
28
- commandAgent,
28
+ commandAgents,
29
29
  commandProjects,
30
- commandIssueAlias,
30
+ commandAgentsAlias,
31
31
  commandEditAlias,
32
+ commandIssueAlias,
32
33
  commandProjectsAlias,
33
34
  ]),
34
35
  Command.provide(Settings.layer),
@@ -0,0 +1,11 @@
1
+ import { Command } from "effect/unstable/cli"
2
+ import { CurrentIssueSource } from "../../CurrentIssueSource.ts"
3
+ import { Settings } from "../../Settings.ts"
4
+ import { addOrUpdatePreset } from "../../Presets.ts"
5
+
6
+ export const commandAgentsAdd = Command.make("add").pipe(
7
+ Command.withDescription("Add a new CLI agent preset"),
8
+ Command.withHandler(() => addOrUpdatePreset()),
9
+ Command.provide(Settings.layer),
10
+ Command.provide(CurrentIssueSource.layer),
11
+ )
@@ -0,0 +1,25 @@
1
+ import { Effect } from "effect"
2
+ import { Command } from "effect/unstable/cli"
3
+ import { Settings } from "../../Settings.ts"
4
+ import { CurrentIssueSource } from "../../CurrentIssueSource.ts"
5
+ import {
6
+ addOrUpdatePreset,
7
+ getAllCliAgentPresets,
8
+ selectCliAgentPreset,
9
+ } from "../../Presets.ts"
10
+
11
+ export const commandAgentsEdit = Command.make("edit").pipe(
12
+ Command.withDescription("Modify a CLI agent preset"),
13
+ Command.withHandler(
14
+ Effect.fnUntraced(function* () {
15
+ const projects = yield* getAllCliAgentPresets
16
+ if (projects.length === 0) {
17
+ return yield* Effect.log("No presets available to edit.")
18
+ }
19
+ const preset = yield* selectCliAgentPreset
20
+ yield* addOrUpdatePreset({ existing: preset })
21
+ }),
22
+ ),
23
+ Command.provide(Settings.layer),
24
+ Command.provide(CurrentIssueSource.layer),
25
+ )
@@ -0,0 +1,43 @@
1
+ import { Effect } from "effect"
2
+ import { Command } from "effect/unstable/cli"
3
+ import { IssueSource } from "../../IssueSource.ts"
4
+ import { CurrentIssueSource } from "../../CurrentIssueSource.ts"
5
+ import { Settings } from "../../Settings.ts"
6
+ import { getAllCliAgentPresets } from "../../Presets.ts"
7
+
8
+ export const commandAgentsLs = Command.make("ls").pipe(
9
+ Command.withDescription("List all configured CLI agent presets"),
10
+ Command.withHandler(
11
+ Effect.fnUntraced(function* () {
12
+ const meta = yield* CurrentIssueSource
13
+ const source = yield* IssueSource
14
+
15
+ console.log("Issue source:", meta.name)
16
+ console.log("")
17
+
18
+ const presets = yield* getAllCliAgentPresets
19
+
20
+ if (presets.length === 0) {
21
+ console.log(
22
+ "No presets configured yet. Run 'lalph agents add' to get started.",
23
+ )
24
+ return
25
+ }
26
+
27
+ for (const preset of presets) {
28
+ console.log(`Preset: ${preset.id}`)
29
+ yield* source.cliAgentPresetInfo(preset)
30
+ console.log(` CLI agent: ${preset.cliAgent.name}`)
31
+ if (preset.extraArgs.length > 0) {
32
+ console.log(` Extra args: ${preset.extraArgs.join(" ")}`)
33
+ }
34
+ if (preset.commandPrefix.length > 0) {
35
+ console.log(` Command prefix: ${preset.commandPrefix.join(" ")}`)
36
+ }
37
+ console.log("")
38
+ }
39
+ }),
40
+ ),
41
+ Command.provide(Settings.layer),
42
+ Command.provide(CurrentIssueSource.layer),
43
+ )
@@ -0,0 +1,26 @@
1
+ import { Effect, Option } from "effect"
2
+ import { Command } from "effect/unstable/cli"
3
+ import { Settings } from "../../Settings.ts"
4
+ import { CurrentIssueSource } from "../../CurrentIssueSource.ts"
5
+ import {
6
+ allCliAgentPresets,
7
+ getAllCliAgentPresets,
8
+ selectCliAgentPreset,
9
+ } from "../../Presets.ts"
10
+
11
+ export const commandAgentsRm = Command.make("rm").pipe(
12
+ Command.withDescription("Remove a CLI agent preset"),
13
+ Command.withHandler(
14
+ Effect.fnUntraced(function* () {
15
+ const presets = yield* getAllCliAgentPresets
16
+ if (presets.length === 0) {
17
+ return yield* Effect.log("There are no presets to remove.")
18
+ }
19
+ const preset = yield* selectCliAgentPreset
20
+ const newPresets = presets.filter((p) => p.id !== preset.id)
21
+ yield* Settings.set(allCliAgentPresets, Option.some(newPresets))
22
+ }),
23
+ ),
24
+ Command.provide(Settings.layer),
25
+ Command.provide(CurrentIssueSource.layer),
26
+ )
@@ -0,0 +1,22 @@
1
+ import { Command } from "effect/unstable/cli"
2
+ import { commandAgentsLs } from "./agents/ls.ts"
3
+ import { commandAgentsAdd } from "./agents/add.ts"
4
+ import { commandAgentsRm } from "./agents/rm.ts"
5
+ import { commandAgentsEdit } from "./agents/edit.ts"
6
+
7
+ const subcommands = Command.withSubcommands([
8
+ commandAgentsLs,
9
+ commandAgentsAdd,
10
+ commandAgentsEdit,
11
+ commandAgentsRm,
12
+ ])
13
+
14
+ export const commandAgents = Command.make("agents").pipe(
15
+ Command.withDescription("Manage CLI agent presets"),
16
+ subcommands,
17
+ )
18
+
19
+ export const commandAgentsAlias = Command.make("a").pipe(
20
+ Command.withDescription("Alias for 'agents' command"),
21
+ subcommands,
22
+ )
@@ -1,6 +1,6 @@
1
1
  import { Command } from "effect/unstable/cli"
2
2
  import { CurrentIssueSource } from "../CurrentIssueSource.ts"
3
- import { Effect, flow, Layer, Option, Schema } from "effect"
3
+ import { Effect, flow, Option, Schema } from "effect"
4
4
  import { IssueSource } from "../IssueSource.ts"
5
5
  import { PrdIssue } from "../domain/PrdIssue.ts"
6
6
  import * as Yaml from "yaml"
@@ -31,8 +31,6 @@ const FrontMatterSchema = Schema.toCodecJson(
31
31
  const handler = flow(
32
32
  Command.withHandler(
33
33
  Effect.fnUntraced(function* () {
34
- const source = yield* IssueSource
35
- const projectId = yield* CurrentProjectId
36
34
  const editor = yield* Editor
37
35
 
38
36
  const content = yield* editor.editTemp({
@@ -66,26 +64,24 @@ const handler = flow(
66
64
  )
67
65
  const description = lines.slice(descriptionStartIndex).join("\n").trim()
68
66
 
69
- const created = yield* source.createIssue(
70
- projectId,
71
- new PrdIssue({
72
- id: null,
73
- ...frontMatter,
74
- description,
75
- state: "todo",
76
- }),
77
- )
78
- console.log(`Created issue with ID: ${created.id}`)
79
- console.log(`URL: ${created.url}`)
80
- }, Effect.scoped),
81
- ),
82
- Command.provide(
83
- Layer.mergeAll(
84
- layerProjectIdPrompt,
85
- CurrentIssueSource.layer,
86
- Editor.layer,
87
- ),
67
+ yield* Effect.gen(function* () {
68
+ const source = yield* IssueSource
69
+ const projectId = yield* CurrentProjectId
70
+ const created = yield* source.createIssue(
71
+ projectId,
72
+ new PrdIssue({
73
+ id: null,
74
+ ...frontMatter,
75
+ description,
76
+ state: "todo",
77
+ }),
78
+ )
79
+ console.log(`Created issue with ID: ${created.id}`)
80
+ console.log(`URL: ${created.url}`)
81
+ }).pipe(Effect.provide([layerProjectIdPrompt, CurrentIssueSource.layer]))
82
+ }),
88
83
  ),
84
+ Command.provide(Editor.layer),
89
85
  )
90
86
 
91
87
  export const commandIssue = Command.make("issue").pipe(
@@ -6,8 +6,9 @@ import { layerProjectIdPrompt } from "../../Projects.ts"
6
6
  import { PromptGen } from "../../PromptGen.ts"
7
7
  import { Settings } from "../../Settings.ts"
8
8
  import { Worktree } from "../../Worktree.ts"
9
- import { getCommandPrefix, getOrSelectCliAgent } from "../agent.ts"
10
9
  import { commandRoot } from "../root.ts"
10
+ import { getDefaultCliAgentPreset } from "../../Presets.ts"
11
+ import { CurrentIssueSource } from "../../CurrentIssueSource.ts"
11
12
 
12
13
  const specificationPath = Argument.path("spec", {
13
14
  pathType: "file",
@@ -29,8 +30,7 @@ export const commandPlanTasks = Command.make("tasks", {
29
30
  const fs = yield* FileSystem.FileSystem
30
31
  const pathService = yield* Path.Path
31
32
  const worktree = yield* Worktree
32
- const cliAgent = yield* getOrSelectCliAgent
33
- const commandPrefix = yield* getCommandPrefix
33
+ const preset = yield* getDefaultCliAgentPreset
34
34
 
35
35
  const content = yield* fs.readFileString(specificationPath)
36
36
  const relative = pathService.relative(
@@ -46,15 +46,15 @@ export const commandPlanTasks = Command.make("tasks", {
46
46
  yield* agentTasker({
47
47
  specsDirectory,
48
48
  specificationPath: relative,
49
- commandPrefix,
50
- cliAgent,
49
+ preset,
51
50
  })
52
51
  },
53
52
  Effect.provide([
54
53
  Settings.layer,
55
54
  PromptGen.layer,
56
55
  Prd.layerProvided.pipe(Layer.provide(layerProjectIdPrompt)),
57
- Worktree.layer.pipe(Layer.provide(layerProjectIdPrompt)),
56
+ CurrentIssueSource.layer,
57
+ Settings.layer,
58
58
  ]),
59
59
  ),
60
60
  ),
@@ -2,8 +2,6 @@ import { Data, Effect, FileSystem, Option, Path, pipe, Schema } from "effect"
2
2
  import { PromptGen } from "../PromptGen.ts"
3
3
  import { Prd } from "../Prd.ts"
4
4
  import { Worktree } from "../Worktree.ts"
5
- import type { ChildProcess } from "effect/unstable/process"
6
- import { getCommandPrefix, getOrSelectCliAgent } from "./agent.ts"
7
5
  import { Command, Flag } from "effect/unstable/cli"
8
6
  import { CurrentIssueSource } from "../CurrentIssueSource.ts"
9
7
  import { commandRoot } from "./root.ts"
@@ -13,6 +11,7 @@ import { agentPlanner } from "../Agents/planner.ts"
13
11
  import { agentTasker } from "../Agents/tasker.ts"
14
12
  import { commandPlanTasks } from "./plan/tasks.ts"
15
13
  import { Editor } from "../Editor.ts"
14
+ import { getDefaultCliAgentPreset } from "../Presets.ts"
16
15
 
17
16
  const dangerous = Flag.boolean("dangerous").pipe(
18
17
  Flag.withAlias("d"),
@@ -45,13 +44,11 @@ export const commandPlan = Command.make("plan", {
45
44
  ? yield* addOrUpdateProject()
46
45
  : yield* selectProject
47
46
  const { specsDirectory } = yield* commandRoot
48
- const commandPrefix = yield* getCommandPrefix
49
47
 
50
48
  yield* plan({
51
49
  plan: thePlan.value,
52
50
  specsDirectory,
53
51
  targetBranch: project.targetBranch,
54
- commandPrefix,
55
52
  dangerous,
56
53
  }).pipe(Effect.provideService(CurrentProjectId, project.id))
57
54
  },
@@ -66,23 +63,18 @@ const plan = Effect.fnUntraced(
66
63
  readonly plan: string
67
64
  readonly specsDirectory: string
68
65
  readonly targetBranch: Option.Option<string>
69
- readonly commandPrefix: (
70
- command: ChildProcess.Command,
71
- ) => ChildProcess.Command
72
66
  readonly dangerous: boolean
73
67
  }) {
74
68
  const fs = yield* FileSystem.FileSystem
75
69
  const pathService = yield* Path.Path
76
70
  const worktree = yield* Worktree
77
-
78
- const cliAgent = yield* getOrSelectCliAgent
71
+ const preset = yield* getDefaultCliAgentPreset
79
72
 
80
73
  yield* agentPlanner({
81
74
  plan: options.plan,
82
75
  specsDirectory: options.specsDirectory,
83
- commandPrefix: options.commandPrefix,
84
76
  dangerous: options.dangerous,
85
- cliAgent,
77
+ preset,
86
78
  })
87
79
 
88
80
  const planDetails = yield* pipe(
@@ -98,8 +90,7 @@ const plan = Effect.fnUntraced(
98
90
  yield* agentTasker({
99
91
  specificationPath: planDetails.specification,
100
92
  specsDirectory: options.specsDirectory,
101
- commandPrefix: options.commandPrefix,
102
- cliAgent,
93
+ preset,
103
94
  })
104
95
 
105
96
  if (!worktree.inExisting) {