lalph 0.2.0 → 0.2.2
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 +80 -57
- package/package.json +1 -1
- package/src/Projects.ts +79 -22
- package/src/commands/issue.ts +3 -1
- package/src/commands/projects/add.ts +6 -51
- package/src/commands/projects/edit.ts +3 -0
- package/src/commands/projects/ls.ts +7 -0
- package/src/commands/projects/rm.ts +4 -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
|
@@ -66689,23 +66689,14 @@ const PlatformServices = layer$2;
|
|
|
66689
66689
|
//#endregion
|
|
66690
66690
|
//#region src/domain/Project.ts
|
|
66691
66691
|
const ProjectId = String$1.pipe(brand("lalph/ProjectId"));
|
|
66692
|
-
var Project$1 = class
|
|
66692
|
+
var Project$1 = class extends Class("lalph/Project")({
|
|
66693
66693
|
id: ProjectId,
|
|
66694
66694
|
enabled: Boolean$2,
|
|
66695
66695
|
targetBranch: Option(String$1),
|
|
66696
66696
|
concurrency: Int.check(isGreaterThanOrEqualTo(1)),
|
|
66697
66697
|
gitFlow: Literals(["pr", "commit"]),
|
|
66698
66698
|
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
|
-
};
|
|
66699
|
+
}) {};
|
|
66709
66700
|
|
|
66710
66701
|
//#endregion
|
|
66711
66702
|
//#region src/Kvs.ts
|
|
@@ -151186,8 +151177,8 @@ const agentTimeout = fnUntraced(function* (options) {
|
|
|
151186
151177
|
const layerProjectIdPrompt = effect$1(CurrentProjectId, gen(function* () {
|
|
151187
151178
|
return (yield* selectProject).id;
|
|
151188
151179
|
})).pipe(provide$3(Settings.layer));
|
|
151189
|
-
const allProjects = new Setting("projects",
|
|
151190
|
-
const getAllProjects = Settings.get(allProjects).pipe(map$8(getOrElse$1(() => [
|
|
151180
|
+
const allProjects = new Setting("projects", Array$1(Project$1));
|
|
151181
|
+
const getAllProjects = Settings.get(allProjects).pipe(map$8(getOrElse$1(() => [])));
|
|
151191
151182
|
const projectById = fnUntraced(function* (projectId) {
|
|
151192
151183
|
const projects = yield* getAllProjects;
|
|
151193
151184
|
return findFirst$3(projects, (p) => p.id === projectId);
|
|
@@ -151195,7 +151186,7 @@ const projectById = fnUntraced(function* (projectId) {
|
|
|
151195
151186
|
const allProjectsAtom = (function() {
|
|
151196
151187
|
const read = Settings.runtime.atom(fnUntraced(function* () {
|
|
151197
151188
|
const projects = yield* (yield* Settings).get(allProjects);
|
|
151198
|
-
return getOrElse$1(projects, () => [
|
|
151189
|
+
return getOrElse$1(projects, () => []);
|
|
151199
151190
|
}));
|
|
151200
151191
|
const set = Settings.runtime.fn()(fnUntraced(function* (value, get) {
|
|
151201
151192
|
yield* (yield* Settings).set(allProjects, some$2(value));
|
|
@@ -151219,7 +151210,6 @@ const projectAtom = family((projectId) => {
|
|
|
151219
151210
|
onNone: () => filter$6(projects, (p) => p.id !== projectId),
|
|
151220
151211
|
onSome: (project) => map$12(projects, (p) => p.id === projectId ? project : p)
|
|
151221
151212
|
});
|
|
151222
|
-
if (!isArrayNonEmpty(updatedProjects)) return;
|
|
151223
151213
|
get.set(allProjectsAtom, updatedProjects);
|
|
151224
151214
|
}));
|
|
151225
151215
|
return writable((get) => {
|
|
@@ -151231,9 +151221,11 @@ const projectAtom = family((projectId) => {
|
|
|
151231
151221
|
});
|
|
151232
151222
|
const selectProject = gen(function* () {
|
|
151233
151223
|
const projects = yield* getAllProjects;
|
|
151234
|
-
if (projects.length ===
|
|
151235
|
-
|
|
151236
|
-
|
|
151224
|
+
if (projects.length === 0) return yield* welcomeWizard;
|
|
151225
|
+
else if (projects.length === 1) {
|
|
151226
|
+
const project = projects[0];
|
|
151227
|
+
yield* log$1(`Using project: ${project.id}`);
|
|
151228
|
+
return project;
|
|
151237
151229
|
}
|
|
151238
151230
|
return yield* autoComplete({
|
|
151239
151231
|
message: "Select a project:",
|
|
@@ -151243,6 +151235,58 @@ const selectProject = gen(function* () {
|
|
|
151243
151235
|
}))
|
|
151244
151236
|
});
|
|
151245
151237
|
});
|
|
151238
|
+
const welcomeWizard = gen(function* () {
|
|
151239
|
+
const welcome = [
|
|
151240
|
+
" .--.",
|
|
151241
|
+
" |^()^| lalph",
|
|
151242
|
+
" '--'",
|
|
151243
|
+
"",
|
|
151244
|
+
"Welcome! Let's add your first project.",
|
|
151245
|
+
"Projects let you configure how lalph runs tasks and integrations",
|
|
151246
|
+
"(like issue filters, concurrency, and git flow).",
|
|
151247
|
+
""
|
|
151248
|
+
].join("\n");
|
|
151249
|
+
console.log(welcome);
|
|
151250
|
+
return yield* addProject;
|
|
151251
|
+
});
|
|
151252
|
+
const addProject = gen(function* () {
|
|
151253
|
+
const projects = yield* getAllProjects;
|
|
151254
|
+
const id = yield* text$2({
|
|
151255
|
+
message: "Name",
|
|
151256
|
+
validate(input) {
|
|
151257
|
+
input = input.trim();
|
|
151258
|
+
if (input.length === 0) return fail$4("Project name cannot be empty");
|
|
151259
|
+
else if (projects.some((p) => p.id === input)) return fail$4("Project already exists");
|
|
151260
|
+
return succeed$1(input);
|
|
151261
|
+
}
|
|
151262
|
+
});
|
|
151263
|
+
const concurrency = yield* integer$2({
|
|
151264
|
+
message: "Concurrency",
|
|
151265
|
+
min: 1
|
|
151266
|
+
});
|
|
151267
|
+
const targetBranch = pipe(yield* text$2({ message: "Target branch (leave empty to use HEAD)" }), trim, liftPredicate(isNonEmpty));
|
|
151268
|
+
const gitFlow = yield* select({
|
|
151269
|
+
message: "Git flow",
|
|
151270
|
+
choices: [{
|
|
151271
|
+
title: "Pull Request",
|
|
151272
|
+
value: "pr"
|
|
151273
|
+
}, {
|
|
151274
|
+
title: "Commit",
|
|
151275
|
+
value: "commit"
|
|
151276
|
+
}]
|
|
151277
|
+
});
|
|
151278
|
+
const reviewAgent = yield* toggle({ message: "Enable review agent?" });
|
|
151279
|
+
const project = new Project$1({
|
|
151280
|
+
id: ProjectId.makeUnsafe(id),
|
|
151281
|
+
enabled: true,
|
|
151282
|
+
concurrency,
|
|
151283
|
+
targetBranch,
|
|
151284
|
+
gitFlow,
|
|
151285
|
+
reviewAgent
|
|
151286
|
+
});
|
|
151287
|
+
yield* Settings.set(allProjects, some$2([...projects, project]));
|
|
151288
|
+
return project;
|
|
151289
|
+
});
|
|
151246
151290
|
|
|
151247
151291
|
//#endregion
|
|
151248
151292
|
//#region src/commands/root.ts
|
|
@@ -151403,7 +151447,13 @@ const commandRoot = make$35("lalph", {
|
|
|
151403
151447
|
}).pipe(withHandler(fnUntraced(function* ({ iterations, maxIterationMinutes, stallMinutes, specsDirectory }) {
|
|
151404
151448
|
const commandPrefix = yield* getCommandPrefix;
|
|
151405
151449
|
yield* getOrSelectCliAgent;
|
|
151406
|
-
|
|
151450
|
+
let allProjects = yield* getAllProjects;
|
|
151451
|
+
if (allProjects.length === 0) {
|
|
151452
|
+
yield* welcomeWizard;
|
|
151453
|
+
allProjects = yield* getAllProjects;
|
|
151454
|
+
}
|
|
151455
|
+
const projects = allProjects.filter((p) => p.enabled);
|
|
151456
|
+
if (projects.length === 0) return yield* log$1("No enabled projects found. Run 'lalph projects toggle' to enable one.");
|
|
151407
151457
|
yield* forEach$3(projects, (project) => runProject({
|
|
151408
151458
|
iterations,
|
|
151409
151459
|
project,
|
|
@@ -151523,7 +151573,7 @@ const handler$1 = flow(withHandler(fnUntraced(function* () {
|
|
|
151523
151573
|
}));
|
|
151524
151574
|
console.log(`Created issue with ID: ${created.id}`);
|
|
151525
151575
|
console.log(`URL: ${created.url}`);
|
|
151526
|
-
}, scoped$1)), provide(mergeAll(CurrentIssueSource.layer
|
|
151576
|
+
}, scoped$1)), provide(mergeAll(CurrentIssueSource.layer).pipe(provideMerge(layerProjectIdPrompt))));
|
|
151527
151577
|
const commandIssue = make$35("issue").pipe(withDescription("Create a new issue in the selected issue source"), handler$1);
|
|
151528
151578
|
const commandIssueAlias = make$35("i").pipe(withDescription("Alias for 'issue' command"), handler$1);
|
|
151529
151579
|
|
|
@@ -151548,7 +151598,7 @@ const commandSource = make$35("source").pipe(withDescription("Select the issue s
|
|
|
151548
151598
|
|
|
151549
151599
|
//#endregion
|
|
151550
151600
|
//#region package.json
|
|
151551
|
-
var version = "0.2.
|
|
151601
|
+
var version = "0.2.2";
|
|
151552
151602
|
|
|
151553
151603
|
//#endregion
|
|
151554
151604
|
//#region src/commands/projects/ls.ts
|
|
@@ -151558,8 +151608,13 @@ const commandProjectsLs = make$35("ls").pipe(withDescription("List all configure
|
|
|
151558
151608
|
console.log("Issue source:", meta.name);
|
|
151559
151609
|
console.log("");
|
|
151560
151610
|
const projects = yield* getAllProjects;
|
|
151611
|
+
if (projects.length === 0) {
|
|
151612
|
+
console.log("No projects configured yet. Run 'lalph projects add' to get started.");
|
|
151613
|
+
return;
|
|
151614
|
+
}
|
|
151561
151615
|
for (const project of projects) {
|
|
151562
151616
|
console.log(`Project: ${project.id}`);
|
|
151617
|
+
console.log(` Enabled: ${project.enabled ? "Yes" : "No"}`);
|
|
151563
151618
|
yield* source.info(project.id);
|
|
151564
151619
|
console.log(` Concurrency: ${project.concurrency}`);
|
|
151565
151620
|
if (isSome(project.targetBranch)) console.log(` Target Branch: ${project.targetBranch.value}`);
|
|
@@ -151572,41 +151627,7 @@ const commandProjectsLs = make$35("ls").pipe(withDescription("List all configure
|
|
|
151572
151627
|
//#endregion
|
|
151573
151628
|
//#region src/commands/projects/add.ts
|
|
151574
151629
|
const commandProjectsAdd = make$35("add").pipe(withDescription("Add a new project"), withHandler(fnUntraced(function* () {
|
|
151575
|
-
const
|
|
151576
|
-
const id = yield* text$2({
|
|
151577
|
-
message: "Name",
|
|
151578
|
-
validate(input) {
|
|
151579
|
-
input = input.trim();
|
|
151580
|
-
if (input.length === 0) return fail$4("Project name cannot be empty");
|
|
151581
|
-
else if (projects.some((p) => p.id === input)) return fail$4(`Project already exists`);
|
|
151582
|
-
return succeed$1(input);
|
|
151583
|
-
}
|
|
151584
|
-
});
|
|
151585
|
-
const concurrency = yield* integer$2({
|
|
151586
|
-
message: "Concurrency",
|
|
151587
|
-
min: 1
|
|
151588
|
-
});
|
|
151589
|
-
const targetBranch = pipe(yield* text$2({ message: "Target branch (leave empty to use HEAD)" }), trim, liftPredicate(isNonEmpty));
|
|
151590
|
-
const gitFlow = yield* select({
|
|
151591
|
-
message: "Git flow",
|
|
151592
|
-
choices: [{
|
|
151593
|
-
title: "Pull Request",
|
|
151594
|
-
value: "pr"
|
|
151595
|
-
}, {
|
|
151596
|
-
title: "Commit",
|
|
151597
|
-
value: "commit"
|
|
151598
|
-
}]
|
|
151599
|
-
});
|
|
151600
|
-
const reviewAgent = yield* toggle({ message: "Enable review agent?" });
|
|
151601
|
-
const project = new Project$1({
|
|
151602
|
-
id: ProjectId.makeUnsafe(id),
|
|
151603
|
-
enabled: true,
|
|
151604
|
-
concurrency,
|
|
151605
|
-
targetBranch,
|
|
151606
|
-
gitFlow,
|
|
151607
|
-
reviewAgent
|
|
151608
|
-
});
|
|
151609
|
-
yield* Settings.set(allProjects, some$2([...projects, project]));
|
|
151630
|
+
const project = yield* addProject;
|
|
151610
151631
|
yield* (yield* IssueSource).settings(project.id);
|
|
151611
151632
|
})), provide(Settings.layer), provide(CurrentIssueSource.layer));
|
|
151612
151633
|
|
|
@@ -151614,9 +151635,9 @@ const commandProjectsAdd = make$35("add").pipe(withDescription("Add a new projec
|
|
|
151614
151635
|
//#region src/commands/projects/rm.ts
|
|
151615
151636
|
const commandProjectsRm = make$35("rm").pipe(withDescription("Remove a project"), withHandler(fnUntraced(function* () {
|
|
151616
151637
|
const projects = yield* getAllProjects;
|
|
151638
|
+
if (projects.length === 0) return yield* log$1("There are no projects to remove.");
|
|
151617
151639
|
const project = yield* selectProject;
|
|
151618
151640
|
const newProjects = projects.filter((p) => p.id !== project.id);
|
|
151619
|
-
if (!isArrayNonEmpty(newProjects)) return yield* log$1("You cannot remove the last remaining project.");
|
|
151620
151641
|
yield* Settings.set(allProjects, some$2(newProjects));
|
|
151621
151642
|
})), provide(Settings.layer));
|
|
151622
151643
|
|
|
@@ -151624,6 +151645,7 @@ const commandProjectsRm = make$35("rm").pipe(withDescription("Remove a project")
|
|
|
151624
151645
|
//#region src/commands/projects/edit.ts
|
|
151625
151646
|
const commandProjectsEdit = make$35("edit").pipe(withDescription("Modify a project"), withHandler(fnUntraced(function* () {
|
|
151626
151647
|
const projects = yield* getAllProjects;
|
|
151648
|
+
if (projects.length === 0) return yield* log$1("No projects available to edit.");
|
|
151627
151649
|
const project = yield* selectProject;
|
|
151628
151650
|
const concurrency = yield* integer$2({
|
|
151629
151651
|
message: "Concurrency",
|
|
@@ -151658,6 +151680,7 @@ const commandProjectsEdit = make$35("edit").pipe(withDescription("Modify a proje
|
|
|
151658
151680
|
//#region src/commands/projects/toggle.ts
|
|
151659
151681
|
const commandProjectsToggle = make$35("toggle").pipe(withDescription("Enable or disable projects"), withHandler(fnUntraced(function* () {
|
|
151660
151682
|
const projects = yield* getAllProjects;
|
|
151683
|
+
if (projects.length === 0) return yield* log$1("No projects available to toggle.");
|
|
151661
151684
|
const enabled = yield* multiSelect({
|
|
151662
151685
|
message: "Select projects to enable",
|
|
151663
151686
|
choices: projects.map((project) => ({
|
package/package.json
CHANGED
package/src/Projects.ts
CHANGED
|
@@ -4,14 +4,15 @@ 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 type { NonEmptyReadonlyArray } from "effect/Array"
|
|
15
16
|
|
|
16
17
|
export const layerProjectIdPrompt = Layer.effect(
|
|
17
18
|
CurrentProjectId,
|
|
@@ -21,17 +22,10 @@ export const layerProjectIdPrompt = Layer.effect(
|
|
|
21
22
|
}),
|
|
22
23
|
).pipe(Layer.provide(Settings.layer))
|
|
23
24
|
|
|
24
|
-
export const allProjects = new Setting(
|
|
25
|
-
"projects",
|
|
26
|
-
Schema.NonEmptyArray(Project),
|
|
27
|
-
)
|
|
25
|
+
export const allProjects = new Setting("projects", Schema.Array(Project))
|
|
28
26
|
|
|
29
27
|
export const getAllProjects = Settings.get(allProjects).pipe(
|
|
30
|
-
Effect.map(
|
|
31
|
-
Option.getOrElse(
|
|
32
|
-
(): NonEmptyReadonlyArray<Project> => [Project.defaultProject],
|
|
33
|
-
),
|
|
34
|
-
),
|
|
28
|
+
Effect.map(Option.getOrElse((): ReadonlyArray<Project> => [])),
|
|
35
29
|
)
|
|
36
30
|
|
|
37
31
|
export const projectById = Effect.fnUntraced(function* (projectId: ProjectId) {
|
|
@@ -44,13 +38,10 @@ export const allProjectsAtom = (function () {
|
|
|
44
38
|
Effect.fnUntraced(function* () {
|
|
45
39
|
const settings = yield* Settings
|
|
46
40
|
const projects = yield* settings.get(allProjects)
|
|
47
|
-
return Option.getOrElse(
|
|
48
|
-
projects,
|
|
49
|
-
(): Array.NonEmptyReadonlyArray<Project> => [Project.defaultProject],
|
|
50
|
-
)
|
|
41
|
+
return Option.getOrElse(projects, (): ReadonlyArray<Project> => [])
|
|
51
42
|
}),
|
|
52
43
|
)
|
|
53
|
-
const set = Settings.runtime.fn<
|
|
44
|
+
const set = Settings.runtime.fn<ReadonlyArray<Project>>()(
|
|
54
45
|
Effect.fnUntraced(function* (value, get) {
|
|
55
46
|
const settings = yield* Settings
|
|
56
47
|
yield* settings.set(allProjects, Option.some(value))
|
|
@@ -62,7 +53,7 @@ export const allProjectsAtom = (function () {
|
|
|
62
53
|
get.mount(set)
|
|
63
54
|
return get(read)
|
|
64
55
|
},
|
|
65
|
-
(ctx, value:
|
|
56
|
+
(ctx, value: ReadonlyArray<Project>) => {
|
|
66
57
|
ctx.set(set, value)
|
|
67
58
|
},
|
|
68
59
|
(r) => r(read),
|
|
@@ -93,7 +84,6 @@ export const projectAtom = Atom.family(
|
|
|
93
84
|
onSome: (project) =>
|
|
94
85
|
Array.map(projects, (p) => (p.id === projectId ? project : p)),
|
|
95
86
|
})
|
|
96
|
-
if (!Array.isArrayNonEmpty(updatedProjects)) return
|
|
97
87
|
get.set(allProjectsAtom, updatedProjects)
|
|
98
88
|
}),
|
|
99
89
|
)
|
|
@@ -120,15 +110,82 @@ export class ProjectNotFound extends Data.TaggedError("ProjectNotFound")<{
|
|
|
120
110
|
|
|
121
111
|
export const selectProject = Effect.gen(function* () {
|
|
122
112
|
const projects = yield* getAllProjects
|
|
123
|
-
if (projects.length ===
|
|
124
|
-
yield*
|
|
125
|
-
|
|
113
|
+
if (projects.length === 0) {
|
|
114
|
+
return yield* welcomeWizard
|
|
115
|
+
} else if (projects.length === 1) {
|
|
116
|
+
const project = projects[0]!
|
|
117
|
+
yield* Effect.log(`Using project: ${project.id}`)
|
|
118
|
+
return project
|
|
126
119
|
}
|
|
127
|
-
|
|
120
|
+
const selection = yield* Prompt.autoComplete({
|
|
128
121
|
message: "Select a project:",
|
|
129
122
|
choices: projects.map((p) => ({
|
|
130
123
|
title: p.id,
|
|
131
124
|
value: p,
|
|
132
125
|
})),
|
|
133
126
|
})
|
|
127
|
+
return selection!
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
export const welcomeWizard = Effect.gen(function* () {
|
|
131
|
+
const welcome = [
|
|
132
|
+
" .--.",
|
|
133
|
+
" |^()^| lalph",
|
|
134
|
+
" '--'",
|
|
135
|
+
"",
|
|
136
|
+
"Welcome! Let's add your first project.",
|
|
137
|
+
"Projects let you configure how lalph runs tasks and integrations",
|
|
138
|
+
"(like issue filters, concurrency, and git flow).",
|
|
139
|
+
"",
|
|
140
|
+
].join("\n")
|
|
141
|
+
console.log(welcome)
|
|
142
|
+
return yield* addProject
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
export const addProject = Effect.gen(function* () {
|
|
146
|
+
const projects = yield* getAllProjects
|
|
147
|
+
const id = yield* Prompt.text({
|
|
148
|
+
message: "Name",
|
|
149
|
+
validate(input) {
|
|
150
|
+
input = input.trim()
|
|
151
|
+
if (input.length === 0) {
|
|
152
|
+
return Effect.fail("Project name cannot be empty")
|
|
153
|
+
} else if (projects.some((p) => p.id === input)) {
|
|
154
|
+
return Effect.fail("Project already exists")
|
|
155
|
+
}
|
|
156
|
+
return Effect.succeed(input)
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
const concurrency = yield* Prompt.integer({
|
|
160
|
+
message: "Concurrency",
|
|
161
|
+
min: 1,
|
|
162
|
+
})
|
|
163
|
+
const targetBranch = pipe(
|
|
164
|
+
yield* Prompt.text({
|
|
165
|
+
message: "Target branch (leave empty to use HEAD)",
|
|
166
|
+
}),
|
|
167
|
+
String.trim,
|
|
168
|
+
Option.liftPredicate(String.isNonEmpty),
|
|
169
|
+
)
|
|
170
|
+
const gitFlow = yield* Prompt.select({
|
|
171
|
+
message: "Git flow",
|
|
172
|
+
choices: [
|
|
173
|
+
{ title: "Pull Request", value: "pr" },
|
|
174
|
+
{ title: "Commit", value: "commit" },
|
|
175
|
+
] as const,
|
|
176
|
+
})
|
|
177
|
+
const reviewAgent = yield* Prompt.toggle({
|
|
178
|
+
message: "Enable review agent?",
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
const project = new Project({
|
|
182
|
+
id: ProjectId.makeUnsafe(id),
|
|
183
|
+
enabled: true,
|
|
184
|
+
concurrency,
|
|
185
|
+
targetBranch,
|
|
186
|
+
gitFlow,
|
|
187
|
+
reviewAgent,
|
|
188
|
+
})
|
|
189
|
+
yield* Settings.set(allProjects, Option.some([...projects, project]))
|
|
190
|
+
return project
|
|
134
191
|
})
|
package/src/commands/issue.ts
CHANGED
|
@@ -1,60 +1,15 @@
|
|
|
1
|
-
import { Effect
|
|
2
|
-
import { Command
|
|
3
|
-
import {
|
|
4
|
-
import { Settings } from "../../Settings.ts"
|
|
5
|
-
import { Project, ProjectId } from "../../domain/Project.ts"
|
|
6
|
-
import { IssueSource } from "../../IssueSource.ts"
|
|
1
|
+
import { Effect } from "effect"
|
|
2
|
+
import { Command } from "effect/unstable/cli"
|
|
3
|
+
import { addProject } from "../../Projects.ts"
|
|
7
4
|
import { CurrentIssueSource } from "../../IssueSources.ts"
|
|
5
|
+
import { IssueSource } from "../../IssueSource.ts"
|
|
6
|
+
import { Settings } from "../../Settings.ts"
|
|
8
7
|
|
|
9
8
|
export const commandProjectsAdd = Command.make("add").pipe(
|
|
10
9
|
Command.withDescription("Add a new project"),
|
|
11
10
|
Command.withHandler(
|
|
12
11
|
Effect.fnUntraced(function* () {
|
|
13
|
-
const
|
|
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
|
-
|
|
12
|
+
const project = yield* addProject
|
|
58
13
|
const source = yield* IssueSource
|
|
59
14
|
yield* source.settings(project.id)
|
|
60
15
|
}),
|
|
@@ -11,6 +11,9 @@ export const commandProjectsEdit = Command.make("edit").pipe(
|
|
|
11
11
|
Command.withHandler(
|
|
12
12
|
Effect.fnUntraced(function* () {
|
|
13
13
|
const projects = yield* getAllProjects
|
|
14
|
+
if (projects.length === 0) {
|
|
15
|
+
return yield* Effect.log("No projects available to edit.")
|
|
16
|
+
}
|
|
14
17
|
const project = yield* selectProject
|
|
15
18
|
const concurrency = yield* Prompt.integer({
|
|
16
19
|
message: "Concurrency",
|
|
@@ -16,8 +16,15 @@ 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}`)
|
|
27
|
+
console.log(` Enabled: ${project.enabled ? "Yes" : "No"}`)
|
|
21
28
|
yield* source.info(project.id)
|
|
22
29
|
console.log(` Concurrency: ${project.concurrency}`)
|
|
23
30
|
if (Option.isSome(project.targetBranch)) {
|
|
@@ -1,4 +1,4 @@
|
|
|
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"
|
|
@@ -8,13 +8,11 @@ export const commandProjectsRm = Command.make("rm").pipe(
|
|
|
8
8
|
Command.withHandler(
|
|
9
9
|
Effect.fnUntraced(function* () {
|
|
10
10
|
const projects = yield* getAllProjects
|
|
11
|
+
if (projects.length === 0) {
|
|
12
|
+
return yield* Effect.log("There are no projects to remove.")
|
|
13
|
+
}
|
|
11
14
|
const project = yield* selectProject
|
|
12
15
|
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
16
|
yield* Settings.set(allProjects, Option.some(newProjects))
|
|
19
17
|
}),
|
|
20
18
|
),
|
|
@@ -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
|
+
}) {}
|