lalph 0.3.44 → 0.3.46
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/cli.mjs +33572 -29445
- package/package.json +9 -8
- package/src/Agents/chooser.ts +35 -1
- package/src/Agents/reviewer.ts +27 -0
- package/src/Agents/tasker.ts +16 -0
- package/src/Agents/timeout.ts +17 -0
- package/src/Agents/worker.ts +15 -0
- package/src/Clanka.ts +6 -3
- package/src/ClankaModels.ts +59 -40
- package/src/Presets.ts +0 -18
- package/src/PromptGen.ts +33 -15
- package/src/TaskTools.ts +52 -29
- package/src/commands/agents/ls.ts +0 -1
- package/src/commands/plan/tasks.ts +3 -1
- package/src/commands/plan.ts +8 -1
- package/src/commands/root.ts +29 -283
- package/src/domain/CliAgent.ts +30 -2
- package/src/domain/CliAgentPreset.ts +0 -2
package/src/commands/plan.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { selectCliAgentPreset } from "../Presets.ts"
|
|
|
15
15
|
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
|
16
16
|
import { parseBranch } from "../shared/git.ts"
|
|
17
17
|
import type { CliAgentPreset } from "../domain/CliAgentPreset.ts"
|
|
18
|
+
import { ClankaModels } from "../ClankaModels.ts"
|
|
18
19
|
|
|
19
20
|
const dangerous = Flag.boolean("dangerous").pipe(
|
|
20
21
|
Flag.withAlias("d"),
|
|
@@ -74,7 +75,13 @@ export const commandPlan = Command.make("plan", {
|
|
|
74
75
|
dangerous,
|
|
75
76
|
preset,
|
|
76
77
|
}).pipe(Effect.provideService(CurrentProjectId, project.id))
|
|
77
|
-
}).pipe(
|
|
78
|
+
}).pipe(
|
|
79
|
+
Effect.provide([
|
|
80
|
+
Settings.layer,
|
|
81
|
+
CurrentIssueSource.layer,
|
|
82
|
+
ClankaModels.layer,
|
|
83
|
+
]),
|
|
84
|
+
)
|
|
78
85
|
}, Effect.provide(Editor.layer)),
|
|
79
86
|
),
|
|
80
87
|
Command.withSubcommands([commandPlanTasks]),
|
package/src/commands/root.ts
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
Effect,
|
|
6
6
|
FiberSet,
|
|
7
7
|
FileSystem,
|
|
8
|
-
identity,
|
|
9
8
|
Iterable,
|
|
10
9
|
Option,
|
|
11
10
|
Path,
|
|
@@ -44,13 +43,11 @@ import { GitFlow, GitFlowCommit, GitFlowError, GitFlowPR } from "../GitFlow.ts"
|
|
|
44
43
|
import { getAllProjects, welcomeWizard } from "../Projects.ts"
|
|
45
44
|
import type { Project } from "../domain/Project.ts"
|
|
46
45
|
import { getDefaultCliAgentPreset } from "../Presets.ts"
|
|
47
|
-
import { ChosenTaskDeferred } from "../TaskTools.ts"
|
|
48
|
-
import { ClankaModels, type ClankaModel } from "../ClankaModels.ts"
|
|
49
|
-
import { runClanka } from "../Clanka.ts"
|
|
50
46
|
import type { QuitError } from "effect/Terminal"
|
|
51
47
|
import type { TimeoutError } from "effect/Cause"
|
|
52
48
|
import type { ChildProcessSpawner } from "effect/unstable/process"
|
|
53
|
-
import
|
|
49
|
+
import { ClankaModels } from "../ClankaModels.ts"
|
|
50
|
+
import type { AiError } from "effect/unstable/ai/AiError"
|
|
54
51
|
|
|
55
52
|
// Main iteration run logic
|
|
56
53
|
|
|
@@ -71,7 +68,8 @@ const run = Effect.fnUntraced(
|
|
|
71
68
|
| GitFlowError
|
|
72
69
|
| ChosenTaskNotFound
|
|
73
70
|
| RunnerStalled
|
|
74
|
-
| TimeoutError
|
|
71
|
+
| TimeoutError
|
|
72
|
+
| AiError,
|
|
75
73
|
| CurrentProjectId
|
|
76
74
|
| ChildProcessSpawner.ChildProcessSpawner
|
|
77
75
|
| Settings
|
|
@@ -85,6 +83,7 @@ const run = Effect.fnUntraced(
|
|
|
85
83
|
| PromptGen
|
|
86
84
|
| Prd
|
|
87
85
|
| Worktree
|
|
86
|
+
| ClankaModels
|
|
88
87
|
| Scope.Scope
|
|
89
88
|
> {
|
|
90
89
|
const projectId = yield* CurrentProjectId
|
|
@@ -202,13 +201,21 @@ const run = Effect.fnUntraced(
|
|
|
202
201
|
)
|
|
203
202
|
|
|
204
203
|
const promptGen = yield* PromptGen
|
|
205
|
-
const instructions =
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
204
|
+
const instructions = taskPreset.cliAgent.command
|
|
205
|
+
? promptGen.prompt({
|
|
206
|
+
specsDirectory: options.specsDirectory,
|
|
207
|
+
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
208
|
+
task: chosenTask.prd,
|
|
209
|
+
githubPrNumber: chosenTask.githubPrNumber ?? undefined,
|
|
210
|
+
gitFlow,
|
|
211
|
+
})
|
|
212
|
+
: promptGen.promptClanka({
|
|
213
|
+
specsDirectory: options.specsDirectory,
|
|
214
|
+
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
215
|
+
task: chosenTask.prd,
|
|
216
|
+
githubPrNumber: chosenTask.githubPrNumber ?? undefined,
|
|
217
|
+
gitFlow,
|
|
218
|
+
})
|
|
212
219
|
|
|
213
220
|
const exitCode = yield* agentWorker({
|
|
214
221
|
stallTimeout: options.stallTimeout,
|
|
@@ -274,252 +281,6 @@ const run = Effect.fnUntraced(
|
|
|
274
281
|
Effect.provide(Prd.layer, { local: true }),
|
|
275
282
|
)
|
|
276
283
|
|
|
277
|
-
const runWithClanka = Effect.fnUntraced(
|
|
278
|
-
function* (options: {
|
|
279
|
-
readonly startedDeferred: Deferred.Deferred<void>
|
|
280
|
-
readonly targetBranch: Option.Option<string>
|
|
281
|
-
readonly specsDirectory: string
|
|
282
|
-
readonly stallTimeout: Duration.Duration
|
|
283
|
-
readonly runTimeout: Duration.Duration
|
|
284
|
-
readonly review: boolean
|
|
285
|
-
readonly clankaModel: ClankaModel
|
|
286
|
-
}): Effect.fn.Return<
|
|
287
|
-
void,
|
|
288
|
-
| PlatformError.PlatformError
|
|
289
|
-
| Schema.SchemaError
|
|
290
|
-
| IssueSourceError
|
|
291
|
-
| GitFlowError
|
|
292
|
-
| ChosenTaskNotFound
|
|
293
|
-
| RunnerStalled
|
|
294
|
-
| TimeoutError
|
|
295
|
-
| AiError.AiError,
|
|
296
|
-
| CurrentProjectId
|
|
297
|
-
| FileSystem.FileSystem
|
|
298
|
-
| Path.Path
|
|
299
|
-
| Worktree
|
|
300
|
-
| ChildProcessSpawner.ChildProcessSpawner
|
|
301
|
-
| GithubCli
|
|
302
|
-
| IssueSource
|
|
303
|
-
| AtomRegistry.AtomRegistry
|
|
304
|
-
| GitFlow
|
|
305
|
-
| CurrentWorkerState
|
|
306
|
-
| PromptGen
|
|
307
|
-
| ClankaModels
|
|
308
|
-
| Scope.Scope
|
|
309
|
-
| Prd
|
|
310
|
-
> {
|
|
311
|
-
const projectId = yield* CurrentProjectId
|
|
312
|
-
const fs = yield* FileSystem.FileSystem
|
|
313
|
-
const pathService = yield* Path.Path
|
|
314
|
-
const worktree = yield* Worktree
|
|
315
|
-
const gh = yield* GithubCli
|
|
316
|
-
const source = yield* IssueSource
|
|
317
|
-
const gitFlow = yield* GitFlow
|
|
318
|
-
const currentWorker = yield* CurrentWorkerState
|
|
319
|
-
const registry = yield* AtomRegistry.AtomRegistry
|
|
320
|
-
const promptGen = yield* PromptGen
|
|
321
|
-
const models = yield* ClankaModels
|
|
322
|
-
const model = models.get(options.clankaModel)
|
|
323
|
-
|
|
324
|
-
// ensure cleanup of branch after run
|
|
325
|
-
yield* Effect.addFinalizer(
|
|
326
|
-
Effect.fnUntraced(function* () {
|
|
327
|
-
const currentBranchName = yield* worktree
|
|
328
|
-
.currentBranch(worktree.directory)
|
|
329
|
-
.pipe(Effect.option, Effect.map(Option.getOrUndefined))
|
|
330
|
-
if (!currentBranchName) return
|
|
331
|
-
|
|
332
|
-
// enter detached state
|
|
333
|
-
yield* worktree.exec`git checkout --detach ${currentBranchName}`
|
|
334
|
-
// delete the branch
|
|
335
|
-
yield* worktree.exec`git branch -D ${currentBranchName}`
|
|
336
|
-
}, Effect.ignore()),
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
-
let taskId: string | undefined = undefined
|
|
340
|
-
|
|
341
|
-
// setup finalizer to revert issue if we fail
|
|
342
|
-
yield* Effect.addFinalizer(
|
|
343
|
-
Effect.fnUntraced(function* (exit) {
|
|
344
|
-
if (exit._tag === "Success") return
|
|
345
|
-
if (taskId) {
|
|
346
|
-
yield* source.updateIssue({
|
|
347
|
-
projectId,
|
|
348
|
-
issueId: taskId,
|
|
349
|
-
state: "todo",
|
|
350
|
-
})
|
|
351
|
-
}
|
|
352
|
-
}, Effect.ignore()),
|
|
353
|
-
)
|
|
354
|
-
|
|
355
|
-
const taskById = (taskId: string) =>
|
|
356
|
-
AtomRegistry.getResult(registry, currentIssuesAtom(projectId)).pipe(
|
|
357
|
-
Effect.map((issues) => issues.find((entry) => entry.id === taskId)),
|
|
358
|
-
)
|
|
359
|
-
|
|
360
|
-
// 1. Choose task
|
|
361
|
-
// --------------
|
|
362
|
-
|
|
363
|
-
registry.update(currentWorker.state, (s) =>
|
|
364
|
-
s.transitionTo(WorkerStatus.ChoosingTask()),
|
|
365
|
-
)
|
|
366
|
-
|
|
367
|
-
const deferred = ChosenTaskDeferred.of(Deferred.makeUnsafe())
|
|
368
|
-
const chooseResult = yield* runClanka({
|
|
369
|
-
directory: worktree.directory,
|
|
370
|
-
prompt: promptGen.promptChooseClanka({ gitFlow }),
|
|
371
|
-
stallTimeout: options.stallTimeout,
|
|
372
|
-
withChoose: true,
|
|
373
|
-
}).pipe(
|
|
374
|
-
Effect.andThen(Effect.fail(new ChosenTaskNotFound())),
|
|
375
|
-
Effect.provideService(ChosenTaskDeferred, deferred),
|
|
376
|
-
Effect.provide(model),
|
|
377
|
-
Effect.raceFirst(Deferred.await(deferred)),
|
|
378
|
-
Effect.withSpan("Main.choose"),
|
|
379
|
-
)
|
|
380
|
-
|
|
381
|
-
const chosenTask = yield* taskById(chooseResult.taskId)
|
|
382
|
-
if (!chosenTask) {
|
|
383
|
-
return yield* new ChosenTaskNotFound()
|
|
384
|
-
}
|
|
385
|
-
taskId = chooseResult.taskId
|
|
386
|
-
yield* source.updateIssue({
|
|
387
|
-
projectId,
|
|
388
|
-
issueId: taskId,
|
|
389
|
-
state: "in-progress",
|
|
390
|
-
})
|
|
391
|
-
|
|
392
|
-
yield* source.ensureInProgress(projectId, taskId).pipe(
|
|
393
|
-
Effect.timeoutOrElse({
|
|
394
|
-
duration: "1 minute",
|
|
395
|
-
onTimeout: () => Effect.fail(new RunnerStalled()),
|
|
396
|
-
}),
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
yield* Deferred.completeWith(options.startedDeferred, Effect.void)
|
|
400
|
-
|
|
401
|
-
if (gitFlow.requiresGithubPr && chooseResult.githubPrNumber) {
|
|
402
|
-
yield* worktree.exec`gh pr checkout ${chooseResult.githubPrNumber}`
|
|
403
|
-
const feedback = yield* gh.prFeedbackMd(chooseResult.githubPrNumber)
|
|
404
|
-
yield* fs.writeFileString(
|
|
405
|
-
pathService.join(worktree.directory, ".lalph", "feedback.md"),
|
|
406
|
-
feedback,
|
|
407
|
-
)
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const catchStallInReview = <A, E, R>(
|
|
411
|
-
effect: Effect.Effect<A, E | RunnerStalled, R>,
|
|
412
|
-
) =>
|
|
413
|
-
Effect.catchIf(
|
|
414
|
-
effect,
|
|
415
|
-
(u): u is RunnerStalled => u instanceof RunnerStalled,
|
|
416
|
-
Effect.fnUntraced(function* (e) {
|
|
417
|
-
const issues = yield* AtomRegistry.getResult(
|
|
418
|
-
registry,
|
|
419
|
-
currentIssuesAtom(projectId),
|
|
420
|
-
)
|
|
421
|
-
const task = issues.find((entry) => entry.id === taskId)
|
|
422
|
-
const inReview = task?.state === "in-review"
|
|
423
|
-
if (inReview) return
|
|
424
|
-
return yield* e
|
|
425
|
-
}),
|
|
426
|
-
)
|
|
427
|
-
|
|
428
|
-
const cancelled = yield* Effect.gen(function* () {
|
|
429
|
-
//
|
|
430
|
-
// 2. Work on task
|
|
431
|
-
// -----------------------
|
|
432
|
-
|
|
433
|
-
registry.update(currentWorker.state, (s) =>
|
|
434
|
-
s.transitionTo(WorkerStatus.Working({ issueId: taskId })),
|
|
435
|
-
)
|
|
436
|
-
|
|
437
|
-
const instructions = promptGen.promptClanka({
|
|
438
|
-
specsDirectory: options.specsDirectory,
|
|
439
|
-
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
440
|
-
task: chosenTask,
|
|
441
|
-
githubPrNumber: chooseResult.githubPrNumber ?? undefined,
|
|
442
|
-
gitFlow,
|
|
443
|
-
})
|
|
444
|
-
|
|
445
|
-
yield* runClanka({
|
|
446
|
-
directory: worktree.directory,
|
|
447
|
-
system: promptGen.systemClanka(options),
|
|
448
|
-
prompt: instructions,
|
|
449
|
-
stallTimeout: options.stallTimeout,
|
|
450
|
-
}).pipe(Effect.provide(model), Effect.withSpan("Main.worker"))
|
|
451
|
-
|
|
452
|
-
// 3. Review task
|
|
453
|
-
// -----------------------
|
|
454
|
-
|
|
455
|
-
if (options.review) {
|
|
456
|
-
registry.update(currentWorker.state, (s) =>
|
|
457
|
-
s.transitionTo(WorkerStatus.Reviewing({ issueId: taskId })),
|
|
458
|
-
)
|
|
459
|
-
|
|
460
|
-
yield* runClanka({
|
|
461
|
-
directory: worktree.directory,
|
|
462
|
-
system: promptGen.systemClanka(options),
|
|
463
|
-
prompt: promptGen.promptReview({
|
|
464
|
-
prompt: instructions,
|
|
465
|
-
gitFlow,
|
|
466
|
-
}),
|
|
467
|
-
}).pipe(
|
|
468
|
-
Effect.provide(model),
|
|
469
|
-
catchStallInReview,
|
|
470
|
-
Effect.withSpan("Main.review"),
|
|
471
|
-
)
|
|
472
|
-
}
|
|
473
|
-
}).pipe(
|
|
474
|
-
Effect.timeout(options.runTimeout),
|
|
475
|
-
Effect.tapErrorTag("TimeoutError", () =>
|
|
476
|
-
runClanka({
|
|
477
|
-
directory: worktree.directory,
|
|
478
|
-
system: promptGen.systemClanka(options),
|
|
479
|
-
prompt: promptGen.promptTimeoutClanka({
|
|
480
|
-
taskId,
|
|
481
|
-
specsDirectory: options.specsDirectory,
|
|
482
|
-
}),
|
|
483
|
-
stallTimeout: options.stallTimeout,
|
|
484
|
-
}).pipe(Effect.provide(model), Effect.withSpan("Main.timeout")),
|
|
485
|
-
),
|
|
486
|
-
Effect.raceFirst(watchTaskState({ issueId: taskId })),
|
|
487
|
-
Effect.as(false),
|
|
488
|
-
Effect.catchTag("TaskStateChanged", (error) =>
|
|
489
|
-
Effect.log(
|
|
490
|
-
`Task ${error.issueId} moved to ${error.state}; cancelling run.`,
|
|
491
|
-
).pipe(Effect.as(true)),
|
|
492
|
-
),
|
|
493
|
-
)
|
|
494
|
-
|
|
495
|
-
if (cancelled) return
|
|
496
|
-
|
|
497
|
-
yield* gitFlow.postWork({
|
|
498
|
-
worktree,
|
|
499
|
-
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
500
|
-
issueId: taskId,
|
|
501
|
-
})
|
|
502
|
-
|
|
503
|
-
const task = yield* taskById(taskId)
|
|
504
|
-
if (task?.autoMerge) {
|
|
505
|
-
yield* gitFlow.autoMerge({
|
|
506
|
-
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
507
|
-
issueId: taskId,
|
|
508
|
-
worktree,
|
|
509
|
-
})
|
|
510
|
-
}
|
|
511
|
-
},
|
|
512
|
-
Effect.scoped,
|
|
513
|
-
Effect.provide(Prd.layer, { local: true }),
|
|
514
|
-
)
|
|
515
|
-
|
|
516
|
-
type RunEffects = ReturnType<typeof run> | ReturnType<typeof runWithClanka>
|
|
517
|
-
type RunEffect = Effect.Effect<
|
|
518
|
-
void,
|
|
519
|
-
Effect.Error<RunEffects>,
|
|
520
|
-
Effect.Services<RunEffects>
|
|
521
|
-
>
|
|
522
|
-
|
|
523
284
|
const runProject = Effect.fnUntraced(
|
|
524
285
|
function* (options: {
|
|
525
286
|
readonly iterations: number
|
|
@@ -527,7 +288,6 @@ const runProject = Effect.fnUntraced(
|
|
|
527
288
|
readonly specsDirectory: string
|
|
528
289
|
readonly stallTimeout: Duration.Duration
|
|
529
290
|
readonly runTimeout: Duration.Duration
|
|
530
|
-
readonly clankaModel: ClankaModel | undefined
|
|
531
291
|
}) {
|
|
532
292
|
const isFinite = Number.isFinite(options.iterations)
|
|
533
293
|
const iterationsDisplay = isFinite ? options.iterations : "unlimited"
|
|
@@ -558,26 +318,14 @@ const runProject = Effect.fnUntraced(
|
|
|
558
318
|
|
|
559
319
|
yield* checkForWork.pipe(
|
|
560
320
|
Effect.andThen(
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
review: options.project.reviewAgent,
|
|
570
|
-
clankaModel: options.clankaModel,
|
|
571
|
-
})
|
|
572
|
-
: run({
|
|
573
|
-
startedDeferred,
|
|
574
|
-
targetBranch: options.project.targetBranch,
|
|
575
|
-
specsDirectory: options.specsDirectory,
|
|
576
|
-
stallTimeout: options.stallTimeout,
|
|
577
|
-
runTimeout: options.runTimeout,
|
|
578
|
-
review: options.project.reviewAgent,
|
|
579
|
-
}),
|
|
580
|
-
).pipe(
|
|
321
|
+
run({
|
|
322
|
+
startedDeferred,
|
|
323
|
+
targetBranch: options.project.targetBranch,
|
|
324
|
+
specsDirectory: options.specsDirectory,
|
|
325
|
+
stallTimeout: options.stallTimeout,
|
|
326
|
+
runTimeout: options.runTimeout,
|
|
327
|
+
review: options.project.reviewAgent,
|
|
328
|
+
}).pipe(
|
|
581
329
|
Effect.provide(
|
|
582
330
|
options.project.gitFlow === "commit" ? GitFlowCommit : GitFlowPR,
|
|
583
331
|
{ local: true },
|
|
@@ -585,7 +333,6 @@ const runProject = Effect.fnUntraced(
|
|
|
585
333
|
withWorkerState(options.project.id),
|
|
586
334
|
),
|
|
587
335
|
),
|
|
588
|
-
(_) => _,
|
|
589
336
|
Effect.catchTags({
|
|
590
337
|
NoMoreWork(_error) {
|
|
591
338
|
if (isFinite) {
|
|
@@ -692,7 +439,7 @@ export const commandRoot = Command.make("lalph", {
|
|
|
692
439
|
stallMinutes,
|
|
693
440
|
specsDirectory,
|
|
694
441
|
}) {
|
|
695
|
-
|
|
442
|
+
yield* getDefaultCliAgentPreset
|
|
696
443
|
|
|
697
444
|
let allProjects = yield* getAllProjects
|
|
698
445
|
if (allProjects.length === 0) {
|
|
@@ -715,7 +462,6 @@ export const commandRoot = Command.make("lalph", {
|
|
|
715
462
|
specsDirectory,
|
|
716
463
|
stallTimeout: Duration.minutes(stallMinutes),
|
|
717
464
|
runTimeout: Duration.minutes(maxIterationMinutes),
|
|
718
|
-
clankaModel: preset.clankaModel,
|
|
719
465
|
}).pipe(Effect.provideService(CurrentProjectId, project.id)),
|
|
720
466
|
{ concurrency: "unbounded", discard: true },
|
|
721
467
|
)
|
package/src/domain/CliAgent.ts
CHANGED
|
@@ -12,7 +12,7 @@ export class CliAgent<const Id extends string> extends Data.Class<{
|
|
|
12
12
|
id: Id
|
|
13
13
|
name: string
|
|
14
14
|
outputTransformer?: OutputTransformer | undefined
|
|
15
|
-
command
|
|
15
|
+
command?: (options: {
|
|
16
16
|
readonly prompt: string
|
|
17
17
|
readonly prdFilePath: string
|
|
18
18
|
readonly extraArgs: ReadonlyArray<string>
|
|
@@ -28,6 +28,34 @@ export type OutputTransformer = (
|
|
|
28
28
|
stream: Stream.Stream<string, PlatformError.PlatformError>,
|
|
29
29
|
) => Stream.Stream<string, PlatformError.PlatformError>
|
|
30
30
|
|
|
31
|
+
const clanka = new CliAgent({
|
|
32
|
+
id: "clanka",
|
|
33
|
+
name: "clanka",
|
|
34
|
+
commandPlan: ({ prompt, prdFilePath, dangerous }) =>
|
|
35
|
+
ChildProcess.make(
|
|
36
|
+
"opencode",
|
|
37
|
+
[
|
|
38
|
+
"--prompt",
|
|
39
|
+
`@${prdFilePath}
|
|
40
|
+
|
|
41
|
+
${prompt}`,
|
|
42
|
+
],
|
|
43
|
+
{
|
|
44
|
+
extendEnv: true,
|
|
45
|
+
...(dangerous
|
|
46
|
+
? {
|
|
47
|
+
env: {
|
|
48
|
+
OPENCODE_PERMISSION: '{"*":"allow"}',
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
: {}),
|
|
52
|
+
stdout: "inherit",
|
|
53
|
+
stderr: "inherit",
|
|
54
|
+
stdin: "inherit",
|
|
55
|
+
},
|
|
56
|
+
),
|
|
57
|
+
})
|
|
58
|
+
|
|
31
59
|
const opencode = new CliAgent({
|
|
32
60
|
id: "opencode",
|
|
33
61
|
name: "opencode",
|
|
@@ -178,7 +206,7 @@ ${prompt}`,
|
|
|
178
206
|
})`echo ${"Plan mode is not supported for amp."}`,
|
|
179
207
|
})
|
|
180
208
|
|
|
181
|
-
export const allCliAgents = [opencode, claude, codex, amp] as const
|
|
209
|
+
export const allCliAgents = [clanka, opencode, claude, codex, amp] as const
|
|
182
210
|
export type AnyCliAgent = (typeof allCliAgents)[number]
|
|
183
211
|
|
|
184
212
|
export const CliAgentFromId = Schema.Literals(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Array, Effect, identity, Option, Schema } from "effect"
|
|
2
2
|
import { CliAgentFromId } from "./CliAgent.ts"
|
|
3
3
|
import { ChildProcess } from "effect/unstable/process"
|
|
4
|
-
import { ClankaModel } from "../ClankaModels.ts"
|
|
5
4
|
|
|
6
5
|
export const CliAgentPresetId = Schema.NonEmptyString.pipe(
|
|
7
6
|
Schema.brand("lalph/CliAgentPresetId"),
|
|
@@ -16,7 +15,6 @@ export class CliAgentPreset extends Schema.Class<CliAgentPreset>(
|
|
|
16
15
|
commandPrefix: Schema.Array(Schema.String),
|
|
17
16
|
extraArgs: Schema.Array(Schema.String),
|
|
18
17
|
sourceMetadata: Schema.Record(Schema.String, Schema.Any),
|
|
19
|
-
clankaModel: Schema.optionalKey(ClankaModel),
|
|
20
18
|
}) {
|
|
21
19
|
static defaultId = CliAgentPresetId.makeUnsafe("default")
|
|
22
20
|
|