lalph 0.2.1 → 0.2.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/cli.mjs +125 -98
- package/package.json +1 -1
- package/src/Projects.ts +105 -23
- package/src/commands/issue.ts +1 -3
- package/src/commands/plan.ts +14 -11
- package/src/commands/projects/add.ts +4 -57
- package/src/commands/projects/edit.ts +12 -49
- package/src/commands/projects/ls.ts +6 -0
- package/src/commands/projects/rm.ts +6 -6
- package/src/commands/projects/toggle.ts +3 -0
- package/src/commands/root.ts +14 -2
- package/src/domain/Project.ts +2 -11
package/dist/cli.mjs
CHANGED
|
@@ -7188,7 +7188,7 @@ const getOption = /* @__PURE__ */ dual(2, (self, service) => {
|
|
|
7188
7188
|
* @since 4.0.0
|
|
7189
7189
|
* @category Utils
|
|
7190
7190
|
*/
|
|
7191
|
-
const merge$
|
|
7191
|
+
const merge$6 = /* @__PURE__ */ dual(2, (self, that) => {
|
|
7192
7192
|
if (self.mapUnsafe.size === 0) return that;
|
|
7193
7193
|
if (that.mapUnsafe.size === 0) return self;
|
|
7194
7194
|
const map = new Map(self.mapUnsafe);
|
|
@@ -9159,7 +9159,7 @@ const servicesWith$1 = (f) => withFiber$1((fiber) => f(fiber.services));
|
|
|
9159
9159
|
/** @internal */
|
|
9160
9160
|
const provideServices$1 = /* @__PURE__ */ dual(2, (self, services) => {
|
|
9161
9161
|
if (effectIsExit(self)) return self;
|
|
9162
|
-
return updateServices$1(self, merge$
|
|
9162
|
+
return updateServices$1(self, merge$6(services));
|
|
9163
9163
|
});
|
|
9164
9164
|
/** @internal */
|
|
9165
9165
|
const provideService$1 = function() {
|
|
@@ -11960,6 +11960,38 @@ const mergeAllEffect = (layers, memoMap, scope) => {
|
|
|
11960
11960
|
* @category zipping
|
|
11961
11961
|
*/
|
|
11962
11962
|
const mergeAll = (...layers) => fromBuild((memoMap, scope) => mergeAllEffect(layers, memoMap, scope));
|
|
11963
|
+
/**
|
|
11964
|
+
* Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.
|
|
11965
|
+
*
|
|
11966
|
+
* This is a binary version of `mergeAll` that merges exactly two layers or one layer with an array of layers.
|
|
11967
|
+
* The layers are built concurrently and their outputs are combined.
|
|
11968
|
+
*
|
|
11969
|
+
* @example
|
|
11970
|
+
* ```ts
|
|
11971
|
+
* import { Effect, Layer, ServiceMap } from "effect"
|
|
11972
|
+
*
|
|
11973
|
+
* class Database extends ServiceMap.Service<Database, {
|
|
11974
|
+
* readonly query: (sql: string) => Effect.Effect<string>
|
|
11975
|
+
* }>()("Database") {}
|
|
11976
|
+
*
|
|
11977
|
+
* class Logger extends ServiceMap.Service<Logger, {
|
|
11978
|
+
* readonly log: (msg: string) => Effect.Effect<void>
|
|
11979
|
+
* }>()("Logger") {}
|
|
11980
|
+
*
|
|
11981
|
+
* const dbLayer = Layer.succeed(Database)({
|
|
11982
|
+
* query: (sql: string) => Effect.succeed("result")
|
|
11983
|
+
* })
|
|
11984
|
+
* const loggerLayer = Layer.succeed(Logger)({
|
|
11985
|
+
* log: (msg: string) => Effect.sync(() => console.log(msg))
|
|
11986
|
+
* })
|
|
11987
|
+
*
|
|
11988
|
+
* const mergedLayer = Layer.merge(dbLayer, loggerLayer)
|
|
11989
|
+
* ```
|
|
11990
|
+
*
|
|
11991
|
+
* @since 2.0.0
|
|
11992
|
+
* @category zipping
|
|
11993
|
+
*/
|
|
11994
|
+
const merge$5 = /* @__PURE__ */ dual(2, (self, that) => mergeAll(self, ...Array.isArray(that) ? that : [that]));
|
|
11963
11995
|
const provideWith = (self, that, f) => fromBuild((memoMap, scope) => flatMap$4(Array.isArray(that) ? mergeAllEffect(that, memoMap, scope) : that.build(memoMap, scope), (context) => self.build(memoMap, scope).pipe(provideServices$1(context), map$11((merged) => f(merged, context)))));
|
|
11964
11996
|
/**
|
|
11965
11997
|
* Feeds the output services of this builder into the input of the specified
|
|
@@ -12102,7 +12134,7 @@ const provide$3 = /* @__PURE__ */ dual(2, (self, that) => provideWith(self, that
|
|
|
12102
12134
|
* @since 2.0.0
|
|
12103
12135
|
* @category utils
|
|
12104
12136
|
*/
|
|
12105
|
-
const provideMerge = /* @__PURE__ */ dual(2, (self, that) => provideWith(self, that, (self, that) => merge$
|
|
12137
|
+
const provideMerge = /* @__PURE__ */ dual(2, (self, that) => provideWith(self, that, (self, that) => merge$6(that, self)));
|
|
12106
12138
|
/**
|
|
12107
12139
|
* Constructs a layer dynamically based on the output of this layer.
|
|
12108
12140
|
*
|
|
@@ -50856,7 +50888,7 @@ const TypeId$27 = "~effect/Cache";
|
|
|
50856
50888
|
*/
|
|
50857
50889
|
const makeWith$1 = (options) => servicesWith$1((services) => {
|
|
50858
50890
|
const self = Object.create(Proto$12);
|
|
50859
|
-
self.lookup = (key) => updateServices$1(options.lookup(key), (input) => merge$
|
|
50891
|
+
self.lookup = (key) => updateServices$1(options.lookup(key), (input) => merge$6(services, input));
|
|
50860
50892
|
self.map = make$45();
|
|
50861
50893
|
self.capacity = options.capacity;
|
|
50862
50894
|
self.timeToLive = options.timeToLive ? (exit, key) => fromDurationInputUnsafe(options.timeToLive(exit, key)) : defaultTimeToLive;
|
|
@@ -58544,7 +58576,7 @@ const SpanNameGenerator$1 = /* @__PURE__ */ Reference("effect/http/HttpClient/Sp
|
|
|
58544
58576
|
/**
|
|
58545
58577
|
* @since 4.0.0
|
|
58546
58578
|
*/
|
|
58547
|
-
const layerMergedServices = (effect) => effect$1(HttpClient)(servicesWith((services) => map$8(effect, (client) => transformResponse(client, updateServices((input) => merge$
|
|
58579
|
+
const layerMergedServices = (effect) => effect$1(HttpClient)(servicesWith((services) => map$8(effect, (client) => transformResponse(client, updateServices((input) => merge$6(services, input))))));
|
|
58548
58580
|
const responseRegistry = /* @__PURE__ */ (() => {
|
|
58549
58581
|
if ("FinalizationRegistry" in globalThis && globalThis.FinalizationRegistry) {
|
|
58550
58582
|
const registry = /* @__PURE__ */ new FinalizationRegistry((controller) => {
|
|
@@ -59849,7 +59881,7 @@ const fromWebSocket = (acquire, options) => withFiber((fiber) => {
|
|
|
59849
59881
|
latch.openUnsafe();
|
|
59850
59882
|
if (opts?.onOpen) yield* opts.onOpen;
|
|
59851
59883
|
return yield* join(fiberSet).pipe(catchFilter(SocketCloseError.filterClean((_) => !closeCodeIsError(_)), (_) => void_$1));
|
|
59852
|
-
})).pipe(updateServices((input) => merge$
|
|
59884
|
+
})).pipe(updateServices((input) => merge$6(acquireContext, input)), ensuring$2(sync(() => {
|
|
59853
59885
|
latch.closeUnsafe();
|
|
59854
59886
|
currentWS = void 0;
|
|
59855
59887
|
})));
|
|
@@ -66689,23 +66721,14 @@ const PlatformServices = layer$2;
|
|
|
66689
66721
|
//#endregion
|
|
66690
66722
|
//#region src/domain/Project.ts
|
|
66691
66723
|
const ProjectId = String$1.pipe(brand("lalph/ProjectId"));
|
|
66692
|
-
var Project$1 = class
|
|
66724
|
+
var Project$1 = class extends Class("lalph/Project")({
|
|
66693
66725
|
id: ProjectId,
|
|
66694
66726
|
enabled: Boolean$2,
|
|
66695
66727
|
targetBranch: Option(String$1),
|
|
66696
66728
|
concurrency: Int.check(isGreaterThanOrEqualTo(1)),
|
|
66697
66729
|
gitFlow: Literals(["pr", "commit"]),
|
|
66698
66730
|
reviewAgent: Boolean$2
|
|
66699
|
-
}) {
|
|
66700
|
-
static defaultProject = new Project$1({
|
|
66701
|
-
id: ProjectId.makeUnsafe("default"),
|
|
66702
|
-
enabled: true,
|
|
66703
|
-
targetBranch: none$3(),
|
|
66704
|
-
concurrency: 1,
|
|
66705
|
-
gitFlow: "pr",
|
|
66706
|
-
reviewAgent: true
|
|
66707
|
-
});
|
|
66708
|
-
};
|
|
66731
|
+
}) {};
|
|
66709
66732
|
|
|
66710
66733
|
//#endregion
|
|
66711
66734
|
//#region src/Kvs.ts
|
|
@@ -151185,9 +151208,9 @@ const agentTimeout = fnUntraced(function* (options) {
|
|
|
151185
151208
|
//#region src/Projects.ts
|
|
151186
151209
|
const layerProjectIdPrompt = effect$1(CurrentProjectId, gen(function* () {
|
|
151187
151210
|
return (yield* selectProject).id;
|
|
151188
|
-
})).pipe(provide$3(Settings.layer));
|
|
151189
|
-
const allProjects = new Setting("projects",
|
|
151190
|
-
const getAllProjects = Settings.get(allProjects).pipe(map$8(getOrElse$1(() => [
|
|
151211
|
+
})).pipe(provide$3(Settings.layer), provide$3(CurrentIssueSource.layer));
|
|
151212
|
+
const allProjects = new Setting("projects", Array$1(Project$1));
|
|
151213
|
+
const getAllProjects = Settings.get(allProjects).pipe(map$8(getOrElse$1(() => [])));
|
|
151191
151214
|
const projectById = fnUntraced(function* (projectId) {
|
|
151192
151215
|
const projects = yield* getAllProjects;
|
|
151193
151216
|
return findFirst$3(projects, (p) => p.id === projectId);
|
|
@@ -151195,7 +151218,7 @@ const projectById = fnUntraced(function* (projectId) {
|
|
|
151195
151218
|
const allProjectsAtom = (function() {
|
|
151196
151219
|
const read = Settings.runtime.atom(fnUntraced(function* () {
|
|
151197
151220
|
const projects = yield* (yield* Settings).get(allProjects);
|
|
151198
|
-
return getOrElse$1(projects, () => [
|
|
151221
|
+
return getOrElse$1(projects, () => []);
|
|
151199
151222
|
}));
|
|
151200
151223
|
const set = Settings.runtime.fn()(fnUntraced(function* (value, get) {
|
|
151201
151224
|
yield* (yield* Settings).set(allProjects, some$2(value));
|
|
@@ -151219,7 +151242,6 @@ const projectAtom = family((projectId) => {
|
|
|
151219
151242
|
onNone: () => filter$6(projects, (p) => p.id !== projectId),
|
|
151220
151243
|
onSome: (project) => map$12(projects, (p) => p.id === projectId ? project : p)
|
|
151221
151244
|
});
|
|
151222
|
-
if (!isArrayNonEmpty(updatedProjects)) return;
|
|
151223
151245
|
get.set(allProjectsAtom, updatedProjects);
|
|
151224
151246
|
}));
|
|
151225
151247
|
return writable((get) => {
|
|
@@ -151231,9 +151253,11 @@ const projectAtom = family((projectId) => {
|
|
|
151231
151253
|
});
|
|
151232
151254
|
const selectProject = gen(function* () {
|
|
151233
151255
|
const projects = yield* getAllProjects;
|
|
151234
|
-
if (projects.length ===
|
|
151235
|
-
|
|
151236
|
-
|
|
151256
|
+
if (projects.length === 0) return yield* welcomeWizard;
|
|
151257
|
+
else if (projects.length === 1) {
|
|
151258
|
+
const project = projects[0];
|
|
151259
|
+
yield* log$1(`Using project: ${project.id}`);
|
|
151260
|
+
return project;
|
|
151237
151261
|
}
|
|
151238
151262
|
return yield* autoComplete({
|
|
151239
151263
|
message: "Select a project:",
|
|
@@ -151243,6 +151267,62 @@ const selectProject = gen(function* () {
|
|
|
151243
151267
|
}))
|
|
151244
151268
|
});
|
|
151245
151269
|
});
|
|
151270
|
+
const welcomeWizard = gen(function* () {
|
|
151271
|
+
const welcome = [
|
|
151272
|
+
" .--.",
|
|
151273
|
+
" |^()^| lalph",
|
|
151274
|
+
" '--'",
|
|
151275
|
+
"",
|
|
151276
|
+
"Welcome! Let's add your first project.",
|
|
151277
|
+
"Projects let you configure how lalph runs tasks.",
|
|
151278
|
+
""
|
|
151279
|
+
].join("\n");
|
|
151280
|
+
console.log(welcome);
|
|
151281
|
+
return yield* addOrUpdateProject();
|
|
151282
|
+
});
|
|
151283
|
+
const addOrUpdateProject = fnUntraced(function* (existing) {
|
|
151284
|
+
const projects = yield* getAllProjects;
|
|
151285
|
+
const id = existing ? existing.id : yield* text$2({
|
|
151286
|
+
message: "Project name",
|
|
151287
|
+
validate(input) {
|
|
151288
|
+
input = input.trim();
|
|
151289
|
+
if (input.length === 0) return fail$4("Project name cannot be empty");
|
|
151290
|
+
else if (projects.some((p) => p.id === input)) return fail$4("Project already exists");
|
|
151291
|
+
return succeed$1(input);
|
|
151292
|
+
}
|
|
151293
|
+
});
|
|
151294
|
+
const concurrency = yield* integer$2({
|
|
151295
|
+
message: "Concurrency (number of tasks to run in parallel)",
|
|
151296
|
+
min: 1
|
|
151297
|
+
});
|
|
151298
|
+
const targetBranch = pipe(yield* text$2({ message: "Target branch (leave empty to use HEAD)" }), trim, liftPredicate(isNonEmpty));
|
|
151299
|
+
const gitFlow = yield* select({
|
|
151300
|
+
message: "Git flow",
|
|
151301
|
+
choices: [{
|
|
151302
|
+
title: "Pull Request",
|
|
151303
|
+
description: "Create a pull request for each task",
|
|
151304
|
+
value: "pr"
|
|
151305
|
+
}, {
|
|
151306
|
+
title: "Commit",
|
|
151307
|
+
description: "Tasks are committed directly to the target branch",
|
|
151308
|
+
value: "commit"
|
|
151309
|
+
}]
|
|
151310
|
+
});
|
|
151311
|
+
const reviewAgent = yield* toggle({ message: "Enable review agent?" });
|
|
151312
|
+
const project = new Project$1({
|
|
151313
|
+
id: ProjectId.makeUnsafe(id),
|
|
151314
|
+
enabled: existing ? existing.enabled : true,
|
|
151315
|
+
concurrency,
|
|
151316
|
+
targetBranch,
|
|
151317
|
+
gitFlow,
|
|
151318
|
+
reviewAgent
|
|
151319
|
+
});
|
|
151320
|
+
yield* Settings.set(allProjects, some$2(existing ? projects.map((p) => p.id === project.id ? project : p) : [...projects, project]));
|
|
151321
|
+
const source = yield* IssueSource;
|
|
151322
|
+
yield* source.reset.pipe(provideService(CurrentProjectId, project.id));
|
|
151323
|
+
yield* source.settings(project.id);
|
|
151324
|
+
return project;
|
|
151325
|
+
});
|
|
151246
151326
|
|
|
151247
151327
|
//#endregion
|
|
151248
151328
|
//#region src/commands/root.ts
|
|
@@ -151403,7 +151483,13 @@ const commandRoot = make$35("lalph", {
|
|
|
151403
151483
|
}).pipe(withHandler(fnUntraced(function* ({ iterations, maxIterationMinutes, stallMinutes, specsDirectory }) {
|
|
151404
151484
|
const commandPrefix = yield* getCommandPrefix;
|
|
151405
151485
|
yield* getOrSelectCliAgent;
|
|
151406
|
-
|
|
151486
|
+
let allProjects = yield* getAllProjects;
|
|
151487
|
+
if (allProjects.length === 0) {
|
|
151488
|
+
yield* welcomeWizard;
|
|
151489
|
+
allProjects = yield* getAllProjects;
|
|
151490
|
+
}
|
|
151491
|
+
const projects = allProjects.filter((p) => p.enabled);
|
|
151492
|
+
if (projects.length === 0) return yield* log$1("No enabled projects found. Run 'lalph projects toggle' to enable one.");
|
|
151407
151493
|
yield* forEach$3(projects, (project) => runProject({
|
|
151408
151494
|
iterations,
|
|
151409
151495
|
project,
|
|
@@ -151437,7 +151523,7 @@ const commandPlan = make$35("plan", { dangerous }).pipe(withDescription("Iterate
|
|
|
151437
151523
|
commandPrefix,
|
|
151438
151524
|
dangerous
|
|
151439
151525
|
}).pipe(provideService(CurrentProjectId, project.id));
|
|
151440
|
-
}, provide$1(Settings.layer))));
|
|
151526
|
+
}, provide$1([Settings.layer, CurrentIssueSource.layer]))));
|
|
151441
151527
|
const plan = fnUntraced(function* (options) {
|
|
151442
151528
|
const fs = yield* FileSystem;
|
|
151443
151529
|
const pathService = yield* Path$1;
|
|
@@ -151523,7 +151609,7 @@ const handler$1 = flow(withHandler(fnUntraced(function* () {
|
|
|
151523
151609
|
}));
|
|
151524
151610
|
console.log(`Created issue with ID: ${created.id}`);
|
|
151525
151611
|
console.log(`URL: ${created.url}`);
|
|
151526
|
-
}, scoped$1)), provide(
|
|
151612
|
+
}, scoped$1)), provide(merge$5(layerProjectIdPrompt, CurrentIssueSource.layer)));
|
|
151527
151613
|
const commandIssue = make$35("issue").pipe(withDescription("Create a new issue in the selected issue source"), handler$1);
|
|
151528
151614
|
const commandIssueAlias = make$35("i").pipe(withDescription("Alias for 'issue' command"), handler$1);
|
|
151529
151615
|
|
|
@@ -151548,7 +151634,7 @@ const commandSource = make$35("source").pipe(withDescription("Select the issue s
|
|
|
151548
151634
|
|
|
151549
151635
|
//#endregion
|
|
151550
151636
|
//#region package.json
|
|
151551
|
-
var version = "0.2.
|
|
151637
|
+
var version = "0.2.3";
|
|
151552
151638
|
|
|
151553
151639
|
//#endregion
|
|
151554
151640
|
//#region src/commands/projects/ls.ts
|
|
@@ -151558,6 +151644,10 @@ const commandProjectsLs = make$35("ls").pipe(withDescription("List all configure
|
|
|
151558
151644
|
console.log("Issue source:", meta.name);
|
|
151559
151645
|
console.log("");
|
|
151560
151646
|
const projects = yield* getAllProjects;
|
|
151647
|
+
if (projects.length === 0) {
|
|
151648
|
+
console.log("No projects configured yet. Run 'lalph projects add' to get started.");
|
|
151649
|
+
return;
|
|
151650
|
+
}
|
|
151561
151651
|
for (const project of projects) {
|
|
151562
151652
|
console.log(`Project: ${project.id}`);
|
|
151563
151653
|
console.log(` Enabled: ${project.enabled ? "Yes" : "No"}`);
|
|
@@ -151572,93 +151662,30 @@ const commandProjectsLs = make$35("ls").pipe(withDescription("List all configure
|
|
|
151572
151662
|
|
|
151573
151663
|
//#endregion
|
|
151574
151664
|
//#region src/commands/projects/add.ts
|
|
151575
|
-
const commandProjectsAdd = make$35("add").pipe(withDescription("Add a new project"), withHandler(
|
|
151576
|
-
const projects = yield* getAllProjects;
|
|
151577
|
-
const id = yield* text$2({
|
|
151578
|
-
message: "Name",
|
|
151579
|
-
validate(input) {
|
|
151580
|
-
input = input.trim();
|
|
151581
|
-
if (input.length === 0) return fail$4("Project name cannot be empty");
|
|
151582
|
-
else if (projects.some((p) => p.id === input)) return fail$4(`Project already exists`);
|
|
151583
|
-
return succeed$1(input);
|
|
151584
|
-
}
|
|
151585
|
-
});
|
|
151586
|
-
const concurrency = yield* integer$2({
|
|
151587
|
-
message: "Concurrency",
|
|
151588
|
-
min: 1
|
|
151589
|
-
});
|
|
151590
|
-
const targetBranch = pipe(yield* text$2({ message: "Target branch (leave empty to use HEAD)" }), trim, liftPredicate(isNonEmpty));
|
|
151591
|
-
const gitFlow = yield* select({
|
|
151592
|
-
message: "Git flow",
|
|
151593
|
-
choices: [{
|
|
151594
|
-
title: "Pull Request",
|
|
151595
|
-
value: "pr"
|
|
151596
|
-
}, {
|
|
151597
|
-
title: "Commit",
|
|
151598
|
-
value: "commit"
|
|
151599
|
-
}]
|
|
151600
|
-
});
|
|
151601
|
-
const reviewAgent = yield* toggle({ message: "Enable review agent?" });
|
|
151602
|
-
const project = new Project$1({
|
|
151603
|
-
id: ProjectId.makeUnsafe(id),
|
|
151604
|
-
enabled: true,
|
|
151605
|
-
concurrency,
|
|
151606
|
-
targetBranch,
|
|
151607
|
-
gitFlow,
|
|
151608
|
-
reviewAgent
|
|
151609
|
-
});
|
|
151610
|
-
yield* Settings.set(allProjects, some$2([...projects, project]));
|
|
151611
|
-
yield* (yield* IssueSource).settings(project.id);
|
|
151612
|
-
})), provide(Settings.layer), provide(CurrentIssueSource.layer));
|
|
151665
|
+
const commandProjectsAdd = make$35("add").pipe(withDescription("Add a new project"), withHandler(() => addOrUpdateProject()), provide(Settings.layer), provide(CurrentIssueSource.layer));
|
|
151613
151666
|
|
|
151614
151667
|
//#endregion
|
|
151615
151668
|
//#region src/commands/projects/rm.ts
|
|
151616
151669
|
const commandProjectsRm = make$35("rm").pipe(withDescription("Remove a project"), withHandler(fnUntraced(function* () {
|
|
151617
151670
|
const projects = yield* getAllProjects;
|
|
151671
|
+
if (projects.length === 0) return yield* log$1("There are no projects to remove.");
|
|
151618
151672
|
const project = yield* selectProject;
|
|
151619
151673
|
const newProjects = projects.filter((p) => p.id !== project.id);
|
|
151620
|
-
if (!isArrayNonEmpty(newProjects)) return yield* log$1("You cannot remove the last remaining project.");
|
|
151621
151674
|
yield* Settings.set(allProjects, some$2(newProjects));
|
|
151622
|
-
})), provide(Settings.layer));
|
|
151675
|
+
})), provide(Settings.layer), provide(CurrentIssueSource.layer));
|
|
151623
151676
|
|
|
151624
151677
|
//#endregion
|
|
151625
151678
|
//#region src/commands/projects/edit.ts
|
|
151626
151679
|
const commandProjectsEdit = make$35("edit").pipe(withDescription("Modify a project"), withHandler(fnUntraced(function* () {
|
|
151627
|
-
|
|
151628
|
-
|
|
151629
|
-
const concurrency = yield* integer$2({
|
|
151630
|
-
message: "Concurrency",
|
|
151631
|
-
min: 1
|
|
151632
|
-
});
|
|
151633
|
-
const targetBranch = pipe(yield* text$2({ message: "Target branch (leave empty to use HEAD)" }), trim, liftPredicate(isNonEmpty));
|
|
151634
|
-
const gitFlow = yield* select({
|
|
151635
|
-
message: "Git flow",
|
|
151636
|
-
choices: [{
|
|
151637
|
-
title: "Pull Request",
|
|
151638
|
-
value: "pr"
|
|
151639
|
-
}, {
|
|
151640
|
-
title: "Commit",
|
|
151641
|
-
value: "commit"
|
|
151642
|
-
}]
|
|
151643
|
-
});
|
|
151644
|
-
const reviewAgent = yield* toggle({ message: "Enable review agent?" });
|
|
151645
|
-
const nextProject = new Project$1({
|
|
151646
|
-
...project,
|
|
151647
|
-
concurrency,
|
|
151648
|
-
targetBranch,
|
|
151649
|
-
gitFlow,
|
|
151650
|
-
reviewAgent
|
|
151651
|
-
});
|
|
151652
|
-
yield* Settings.set(allProjects, some$2(map$12(projects, (p) => p.id === nextProject.id ? nextProject : p)));
|
|
151653
|
-
const source = yield* IssueSource;
|
|
151654
|
-
yield* source.reset.pipe(provideService(CurrentProjectId, nextProject.id));
|
|
151655
|
-
yield* source.settings(project.id);
|
|
151680
|
+
if ((yield* getAllProjects).length === 0) return yield* log$1("No projects available to edit.");
|
|
151681
|
+
yield* addOrUpdateProject(yield* selectProject);
|
|
151656
151682
|
})), provide(Settings.layer), provide(CurrentIssueSource.layer));
|
|
151657
151683
|
|
|
151658
151684
|
//#endregion
|
|
151659
151685
|
//#region src/commands/projects/toggle.ts
|
|
151660
151686
|
const commandProjectsToggle = make$35("toggle").pipe(withDescription("Enable or disable projects"), withHandler(fnUntraced(function* () {
|
|
151661
151687
|
const projects = yield* getAllProjects;
|
|
151688
|
+
if (projects.length === 0) return yield* log$1("No projects available to toggle.");
|
|
151662
151689
|
const enabled = yield* multiSelect({
|
|
151663
151690
|
message: "Select projects to enable",
|
|
151664
151691
|
choices: projects.map((project) => ({
|
package/package.json
CHANGED
package/src/Projects.ts
CHANGED
|
@@ -4,14 +4,17 @@ import {
|
|
|
4
4
|
Effect,
|
|
5
5
|
Layer,
|
|
6
6
|
Option,
|
|
7
|
+
pipe,
|
|
7
8
|
PlatformError,
|
|
8
9
|
Schema,
|
|
10
|
+
String,
|
|
9
11
|
} from "effect"
|
|
10
|
-
import { Project,
|
|
12
|
+
import { Project, ProjectId } from "./domain/Project.ts"
|
|
11
13
|
import { AsyncResult, Atom } from "effect/unstable/reactivity"
|
|
12
14
|
import { CurrentProjectId, Setting, Settings } from "./Settings.ts"
|
|
13
15
|
import { Prompt } from "effect/unstable/cli"
|
|
14
|
-
import
|
|
16
|
+
import { IssueSource } from "./IssueSource.ts"
|
|
17
|
+
import { CurrentIssueSource } from "./IssueSources.ts"
|
|
15
18
|
|
|
16
19
|
export const layerProjectIdPrompt = Layer.effect(
|
|
17
20
|
CurrentProjectId,
|
|
@@ -19,19 +22,12 @@ export const layerProjectIdPrompt = Layer.effect(
|
|
|
19
22
|
const project = yield* selectProject
|
|
20
23
|
return project.id
|
|
21
24
|
}),
|
|
22
|
-
).pipe(Layer.provide(Settings.layer))
|
|
25
|
+
).pipe(Layer.provide(Settings.layer), Layer.provide(CurrentIssueSource.layer))
|
|
23
26
|
|
|
24
|
-
export const allProjects = new Setting(
|
|
25
|
-
"projects",
|
|
26
|
-
Schema.NonEmptyArray(Project),
|
|
27
|
-
)
|
|
27
|
+
export const allProjects = new Setting("projects", Schema.Array(Project))
|
|
28
28
|
|
|
29
29
|
export const getAllProjects = Settings.get(allProjects).pipe(
|
|
30
|
-
Effect.map(
|
|
31
|
-
Option.getOrElse(
|
|
32
|
-
(): NonEmptyReadonlyArray<Project> => [Project.defaultProject],
|
|
33
|
-
),
|
|
34
|
-
),
|
|
30
|
+
Effect.map(Option.getOrElse((): ReadonlyArray<Project> => [])),
|
|
35
31
|
)
|
|
36
32
|
|
|
37
33
|
export const projectById = Effect.fnUntraced(function* (projectId: ProjectId) {
|
|
@@ -44,13 +40,10 @@ export const allProjectsAtom = (function () {
|
|
|
44
40
|
Effect.fnUntraced(function* () {
|
|
45
41
|
const settings = yield* Settings
|
|
46
42
|
const projects = yield* settings.get(allProjects)
|
|
47
|
-
return Option.getOrElse(
|
|
48
|
-
projects,
|
|
49
|
-
(): Array.NonEmptyReadonlyArray<Project> => [Project.defaultProject],
|
|
50
|
-
)
|
|
43
|
+
return Option.getOrElse(projects, (): ReadonlyArray<Project> => [])
|
|
51
44
|
}),
|
|
52
45
|
)
|
|
53
|
-
const set = Settings.runtime.fn<
|
|
46
|
+
const set = Settings.runtime.fn<ReadonlyArray<Project>>()(
|
|
54
47
|
Effect.fnUntraced(function* (value, get) {
|
|
55
48
|
const settings = yield* Settings
|
|
56
49
|
yield* settings.set(allProjects, Option.some(value))
|
|
@@ -62,7 +55,7 @@ export const allProjectsAtom = (function () {
|
|
|
62
55
|
get.mount(set)
|
|
63
56
|
return get(read)
|
|
64
57
|
},
|
|
65
|
-
(ctx, value:
|
|
58
|
+
(ctx, value: ReadonlyArray<Project>) => {
|
|
66
59
|
ctx.set(set, value)
|
|
67
60
|
},
|
|
68
61
|
(r) => r(read),
|
|
@@ -93,7 +86,6 @@ export const projectAtom = Atom.family(
|
|
|
93
86
|
onSome: (project) =>
|
|
94
87
|
Array.map(projects, (p) => (p.id === projectId ? project : p)),
|
|
95
88
|
})
|
|
96
|
-
if (!Array.isArrayNonEmpty(updatedProjects)) return
|
|
97
89
|
get.set(allProjectsAtom, updatedProjects)
|
|
98
90
|
}),
|
|
99
91
|
)
|
|
@@ -120,15 +112,105 @@ export class ProjectNotFound extends Data.TaggedError("ProjectNotFound")<{
|
|
|
120
112
|
|
|
121
113
|
export const selectProject = Effect.gen(function* () {
|
|
122
114
|
const projects = yield* getAllProjects
|
|
123
|
-
if (projects.length ===
|
|
124
|
-
yield*
|
|
125
|
-
|
|
115
|
+
if (projects.length === 0) {
|
|
116
|
+
return yield* welcomeWizard
|
|
117
|
+
} else if (projects.length === 1) {
|
|
118
|
+
const project = projects[0]!
|
|
119
|
+
yield* Effect.log(`Using project: ${project.id}`)
|
|
120
|
+
return project
|
|
126
121
|
}
|
|
127
|
-
|
|
122
|
+
const selection = yield* Prompt.autoComplete({
|
|
128
123
|
message: "Select a project:",
|
|
129
124
|
choices: projects.map((p) => ({
|
|
130
125
|
title: p.id,
|
|
131
126
|
value: p,
|
|
132
127
|
})),
|
|
133
128
|
})
|
|
129
|
+
return selection!
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
export const welcomeWizard = Effect.gen(function* () {
|
|
133
|
+
const welcome = [
|
|
134
|
+
" .--.",
|
|
135
|
+
" |^()^| lalph",
|
|
136
|
+
" '--'",
|
|
137
|
+
"",
|
|
138
|
+
"Welcome! Let's add your first project.",
|
|
139
|
+
"Projects let you configure how lalph runs tasks.",
|
|
140
|
+
"",
|
|
141
|
+
].join("\n")
|
|
142
|
+
console.log(welcome)
|
|
143
|
+
return yield* addOrUpdateProject()
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
export const addOrUpdateProject = Effect.fnUntraced(function* (
|
|
147
|
+
existing?: Project,
|
|
148
|
+
) {
|
|
149
|
+
const projects = yield* getAllProjects
|
|
150
|
+
const id = existing
|
|
151
|
+
? existing.id
|
|
152
|
+
: yield* Prompt.text({
|
|
153
|
+
message: "Project name",
|
|
154
|
+
validate(input) {
|
|
155
|
+
input = input.trim()
|
|
156
|
+
if (input.length === 0) {
|
|
157
|
+
return Effect.fail("Project name cannot be empty")
|
|
158
|
+
} else if (projects.some((p) => p.id === input)) {
|
|
159
|
+
return Effect.fail("Project already exists")
|
|
160
|
+
}
|
|
161
|
+
return Effect.succeed(input)
|
|
162
|
+
},
|
|
163
|
+
})
|
|
164
|
+
const concurrency = yield* Prompt.integer({
|
|
165
|
+
message: "Concurrency (number of tasks to run in parallel)",
|
|
166
|
+
min: 1,
|
|
167
|
+
})
|
|
168
|
+
const targetBranch = pipe(
|
|
169
|
+
yield* Prompt.text({
|
|
170
|
+
message: "Target branch (leave empty to use HEAD)",
|
|
171
|
+
}),
|
|
172
|
+
String.trim,
|
|
173
|
+
Option.liftPredicate(String.isNonEmpty),
|
|
174
|
+
)
|
|
175
|
+
const gitFlow = yield* Prompt.select({
|
|
176
|
+
message: "Git flow",
|
|
177
|
+
choices: [
|
|
178
|
+
{
|
|
179
|
+
title: "Pull Request",
|
|
180
|
+
description: "Create a pull request for each task",
|
|
181
|
+
value: "pr",
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
title: "Commit",
|
|
185
|
+
description: "Tasks are committed directly to the target branch",
|
|
186
|
+
value: "commit",
|
|
187
|
+
},
|
|
188
|
+
] as const,
|
|
189
|
+
})
|
|
190
|
+
const reviewAgent = yield* Prompt.toggle({
|
|
191
|
+
message: "Enable review agent?",
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const project = new Project({
|
|
195
|
+
id: ProjectId.makeUnsafe(id),
|
|
196
|
+
enabled: existing ? existing.enabled : true,
|
|
197
|
+
concurrency,
|
|
198
|
+
targetBranch,
|
|
199
|
+
gitFlow,
|
|
200
|
+
reviewAgent,
|
|
201
|
+
})
|
|
202
|
+
yield* Settings.set(
|
|
203
|
+
allProjects,
|
|
204
|
+
Option.some(
|
|
205
|
+
existing
|
|
206
|
+
? projects.map((p) => (p.id === project.id ? project : p))
|
|
207
|
+
: [...projects, project],
|
|
208
|
+
),
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
const source = yield* IssueSource
|
|
212
|
+
yield* source.reset.pipe(Effect.provideService(CurrentProjectId, project.id))
|
|
213
|
+
yield* source.settings(project.id)
|
|
214
|
+
|
|
215
|
+
return project
|
|
134
216
|
})
|
package/src/commands/issue.ts
CHANGED
|
@@ -93,9 +93,7 @@ const handler = flow(
|
|
|
93
93
|
console.log(`URL: ${created.url}`)
|
|
94
94
|
}, Effect.scoped),
|
|
95
95
|
),
|
|
96
|
-
Command.provide(
|
|
97
|
-
Layer.mergeAll(CurrentIssueSource.layer, layerProjectIdPrompt),
|
|
98
|
-
),
|
|
96
|
+
Command.provide(Layer.merge(layerProjectIdPrompt, CurrentIssueSource.layer)),
|
|
99
97
|
)
|
|
100
98
|
|
|
101
99
|
export const commandIssue = Command.make("issue").pipe(
|
package/src/commands/plan.ts
CHANGED
|
@@ -20,17 +20,20 @@ const dangerous = Flag.boolean("dangerous").pipe(
|
|
|
20
20
|
export const commandPlan = Command.make("plan", { dangerous }).pipe(
|
|
21
21
|
Command.withDescription("Iterate on an issue plan and create PRD tasks"),
|
|
22
22
|
Command.withHandler(
|
|
23
|
-
Effect.fnUntraced(
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
Effect.fnUntraced(
|
|
24
|
+
function* ({ dangerous }) {
|
|
25
|
+
const project = yield* selectProject
|
|
26
|
+
const { specsDirectory } = yield* commandRoot
|
|
27
|
+
const commandPrefix = yield* getCommandPrefix
|
|
28
|
+
yield* plan({
|
|
29
|
+
specsDirectory,
|
|
30
|
+
targetBranch: project.targetBranch,
|
|
31
|
+
commandPrefix,
|
|
32
|
+
dangerous,
|
|
33
|
+
}).pipe(Effect.provideService(CurrentProjectId, project.id))
|
|
34
|
+
},
|
|
35
|
+
Effect.provide([Settings.layer, CurrentIssueSource.layer]),
|
|
36
|
+
),
|
|
34
37
|
),
|
|
35
38
|
)
|
|
36
39
|
const plan = Effect.fnUntraced(
|
|
@@ -1,64 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { allProjects, getAllProjects } from "../../Projects.ts"
|
|
4
|
-
import { Settings } from "../../Settings.ts"
|
|
5
|
-
import { Project, ProjectId } from "../../domain/Project.ts"
|
|
6
|
-
import { IssueSource } from "../../IssueSource.ts"
|
|
1
|
+
import { Command } from "effect/unstable/cli"
|
|
2
|
+
import { addOrUpdateProject } from "../../Projects.ts"
|
|
7
3
|
import { CurrentIssueSource } from "../../IssueSources.ts"
|
|
4
|
+
import { Settings } from "../../Settings.ts"
|
|
8
5
|
|
|
9
6
|
export const commandProjectsAdd = Command.make("add").pipe(
|
|
10
7
|
Command.withDescription("Add a new project"),
|
|
11
|
-
Command.withHandler(
|
|
12
|
-
Effect.fnUntraced(function* () {
|
|
13
|
-
const projects = yield* getAllProjects
|
|
14
|
-
const id = yield* Prompt.text({
|
|
15
|
-
message: "Name",
|
|
16
|
-
validate(input) {
|
|
17
|
-
input = input.trim()
|
|
18
|
-
if (input.length === 0) {
|
|
19
|
-
return Effect.fail("Project name cannot be empty")
|
|
20
|
-
} else if (projects.some((p) => p.id === input)) {
|
|
21
|
-
return Effect.fail(`Project already exists`)
|
|
22
|
-
}
|
|
23
|
-
return Effect.succeed(input)
|
|
24
|
-
},
|
|
25
|
-
})
|
|
26
|
-
const concurrency = yield* Prompt.integer({
|
|
27
|
-
message: "Concurrency",
|
|
28
|
-
min: 1,
|
|
29
|
-
})
|
|
30
|
-
const targetBranch = pipe(
|
|
31
|
-
yield* Prompt.text({
|
|
32
|
-
message: "Target branch (leave empty to use HEAD)",
|
|
33
|
-
}),
|
|
34
|
-
String.trim,
|
|
35
|
-
Option.liftPredicate(String.isNonEmpty),
|
|
36
|
-
)
|
|
37
|
-
const gitFlow = yield* Prompt.select({
|
|
38
|
-
message: "Git flow",
|
|
39
|
-
choices: [
|
|
40
|
-
{ title: "Pull Request", value: "pr" },
|
|
41
|
-
{ title: "Commit", value: "commit" },
|
|
42
|
-
] as const,
|
|
43
|
-
})
|
|
44
|
-
const reviewAgent = yield* Prompt.toggle({
|
|
45
|
-
message: "Enable review agent?",
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
const project = new Project({
|
|
49
|
-
id: ProjectId.makeUnsafe(id),
|
|
50
|
-
enabled: true,
|
|
51
|
-
concurrency,
|
|
52
|
-
targetBranch,
|
|
53
|
-
gitFlow,
|
|
54
|
-
reviewAgent,
|
|
55
|
-
})
|
|
56
|
-
yield* Settings.set(allProjects, Option.some([...projects, project]))
|
|
57
|
-
|
|
58
|
-
const source = yield* IssueSource
|
|
59
|
-
yield* source.settings(project.id)
|
|
60
|
-
}),
|
|
61
|
-
),
|
|
8
|
+
Command.withHandler(() => addOrUpdateProject()),
|
|
62
9
|
Command.provide(Settings.layer),
|
|
63
10
|
Command.provide(CurrentIssueSource.layer),
|
|
64
11
|
)
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Command
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { Effect } from "effect"
|
|
2
|
+
import { Command } from "effect/unstable/cli"
|
|
3
|
+
import {
|
|
4
|
+
addOrUpdateProject,
|
|
5
|
+
getAllProjects,
|
|
6
|
+
selectProject,
|
|
7
|
+
} from "../../Projects.ts"
|
|
8
|
+
import { Settings } from "../../Settings.ts"
|
|
7
9
|
import { CurrentIssueSource } from "../../IssueSources.ts"
|
|
8
10
|
|
|
9
11
|
export const commandProjectsEdit = Command.make("edit").pipe(
|
|
@@ -11,50 +13,11 @@ export const commandProjectsEdit = Command.make("edit").pipe(
|
|
|
11
13
|
Command.withHandler(
|
|
12
14
|
Effect.fnUntraced(function* () {
|
|
13
15
|
const projects = yield* getAllProjects
|
|
16
|
+
if (projects.length === 0) {
|
|
17
|
+
return yield* Effect.log("No projects available to edit.")
|
|
18
|
+
}
|
|
14
19
|
const project = yield* selectProject
|
|
15
|
-
|
|
16
|
-
message: "Concurrency",
|
|
17
|
-
min: 1,
|
|
18
|
-
})
|
|
19
|
-
const targetBranch = pipe(
|
|
20
|
-
yield* Prompt.text({
|
|
21
|
-
message: "Target branch (leave empty to use HEAD)",
|
|
22
|
-
}),
|
|
23
|
-
String.trim,
|
|
24
|
-
Option.liftPredicate(String.isNonEmpty),
|
|
25
|
-
)
|
|
26
|
-
const gitFlow = yield* Prompt.select({
|
|
27
|
-
message: "Git flow",
|
|
28
|
-
choices: [
|
|
29
|
-
{ title: "Pull Request", value: "pr" },
|
|
30
|
-
{ title: "Commit", value: "commit" },
|
|
31
|
-
] as const,
|
|
32
|
-
})
|
|
33
|
-
const reviewAgent = yield* Prompt.toggle({
|
|
34
|
-
message: "Enable review agent?",
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
const nextProject = new Project({
|
|
38
|
-
...project,
|
|
39
|
-
concurrency,
|
|
40
|
-
targetBranch,
|
|
41
|
-
gitFlow,
|
|
42
|
-
reviewAgent,
|
|
43
|
-
})
|
|
44
|
-
yield* Settings.set(
|
|
45
|
-
allProjects,
|
|
46
|
-
Option.some(
|
|
47
|
-
Array.map(projects, (p) =>
|
|
48
|
-
p.id === nextProject.id ? nextProject : p,
|
|
49
|
-
),
|
|
50
|
-
),
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
const source = yield* IssueSource
|
|
54
|
-
yield* source.reset.pipe(
|
|
55
|
-
Effect.provideService(CurrentProjectId, nextProject.id),
|
|
56
|
-
)
|
|
57
|
-
yield* source.settings(project.id)
|
|
20
|
+
yield* addOrUpdateProject(project)
|
|
58
21
|
}),
|
|
59
22
|
),
|
|
60
23
|
Command.provide(Settings.layer),
|
|
@@ -16,6 +16,12 @@ export const commandProjectsLs = Command.make("ls").pipe(
|
|
|
16
16
|
|
|
17
17
|
const projects = yield* getAllProjects
|
|
18
18
|
|
|
19
|
+
if (projects.length === 0) {
|
|
20
|
+
console.log(
|
|
21
|
+
"No projects configured yet. Run 'lalph projects add' to get started.",
|
|
22
|
+
)
|
|
23
|
+
return
|
|
24
|
+
}
|
|
19
25
|
for (const project of projects) {
|
|
20
26
|
console.log(`Project: ${project.id}`)
|
|
21
27
|
console.log(` Enabled: ${project.enabled ? "Yes" : "No"}`)
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Effect, Option } from "effect"
|
|
2
2
|
import { Command } from "effect/unstable/cli"
|
|
3
3
|
import { allProjects, getAllProjects, selectProject } from "../../Projects.ts"
|
|
4
4
|
import { Settings } from "../../Settings.ts"
|
|
5
|
+
import { CurrentIssueSource } from "../../IssueSources.ts"
|
|
5
6
|
|
|
6
7
|
export const commandProjectsRm = Command.make("rm").pipe(
|
|
7
8
|
Command.withDescription("Remove a project"),
|
|
8
9
|
Command.withHandler(
|
|
9
10
|
Effect.fnUntraced(function* () {
|
|
10
11
|
const projects = yield* getAllProjects
|
|
12
|
+
if (projects.length === 0) {
|
|
13
|
+
return yield* Effect.log("There are no projects to remove.")
|
|
14
|
+
}
|
|
11
15
|
const project = yield* selectProject
|
|
12
16
|
const newProjects = projects.filter((p) => p.id !== project.id)
|
|
13
|
-
if (!Array.isArrayNonEmpty(newProjects)) {
|
|
14
|
-
return yield* Effect.log(
|
|
15
|
-
"You cannot remove the last remaining project.",
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
17
|
yield* Settings.set(allProjects, Option.some(newProjects))
|
|
19
18
|
}),
|
|
20
19
|
),
|
|
21
20
|
Command.provide(Settings.layer),
|
|
21
|
+
Command.provide(CurrentIssueSource.layer),
|
|
22
22
|
)
|
|
@@ -9,6 +9,9 @@ export const commandProjectsToggle = Command.make("toggle").pipe(
|
|
|
9
9
|
Command.withHandler(
|
|
10
10
|
Effect.fnUntraced(function* () {
|
|
11
11
|
const projects = yield* getAllProjects
|
|
12
|
+
if (projects.length === 0) {
|
|
13
|
+
return yield* Effect.log("No projects available to toggle.")
|
|
14
|
+
}
|
|
12
15
|
const enabled = yield* Prompt.multiSelect({
|
|
13
16
|
message: "Select projects to enable",
|
|
14
17
|
choices: projects.map((project) => ({
|
package/src/commands/root.ts
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
import { WorkerStatus } from "../domain/WorkerState.ts"
|
|
40
40
|
import { GitFlow, GitFlowCommit, GitFlowPR } from "../GitFlow.ts"
|
|
41
41
|
import { parseBranch } from "../shared/git.ts"
|
|
42
|
-
import { getAllProjects } from "../Projects.ts"
|
|
42
|
+
import { getAllProjects, welcomeWizard } from "../Projects.ts"
|
|
43
43
|
import type { Project } from "../domain/Project.ts"
|
|
44
44
|
|
|
45
45
|
// Main iteration run logic
|
|
@@ -384,7 +384,19 @@ export const commandRoot = Command.make("lalph", {
|
|
|
384
384
|
}) {
|
|
385
385
|
const commandPrefix = yield* getCommandPrefix
|
|
386
386
|
yield* getOrSelectCliAgent
|
|
387
|
-
|
|
387
|
+
|
|
388
|
+
let allProjects = yield* getAllProjects
|
|
389
|
+
if (allProjects.length === 0) {
|
|
390
|
+
yield* welcomeWizard
|
|
391
|
+
allProjects = yield* getAllProjects
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const projects = allProjects.filter((p) => p.enabled)
|
|
395
|
+
if (projects.length === 0) {
|
|
396
|
+
return yield* Effect.log(
|
|
397
|
+
"No enabled projects found. Run 'lalph projects toggle' to enable one.",
|
|
398
|
+
)
|
|
399
|
+
}
|
|
388
400
|
yield* Effect.forEach(
|
|
389
401
|
projects,
|
|
390
402
|
(project) =>
|
package/src/domain/Project.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Schema } from "effect"
|
|
2
2
|
|
|
3
3
|
export const ProjectId = Schema.String.pipe(Schema.brand("lalph/ProjectId"))
|
|
4
4
|
export type ProjectId = typeof ProjectId.Type
|
|
@@ -10,13 +10,4 @@ export class Project extends Schema.Class<Project>("lalph/Project")({
|
|
|
10
10
|
concurrency: Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)),
|
|
11
11
|
gitFlow: Schema.Literals(["pr", "commit"]),
|
|
12
12
|
reviewAgent: Schema.Boolean,
|
|
13
|
-
}) {
|
|
14
|
-
static defaultProject = new Project({
|
|
15
|
-
id: ProjectId.makeUnsafe("default"),
|
|
16
|
-
enabled: true,
|
|
17
|
-
targetBranch: Option.none(),
|
|
18
|
-
concurrency: 1,
|
|
19
|
-
gitFlow: "pr",
|
|
20
|
-
reviewAgent: true,
|
|
21
|
-
})
|
|
22
|
-
}
|
|
13
|
+
}) {}
|