lalph 0.1.36 → 0.1.37
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 +56 -38
- package/package.json +1 -1
- package/src/PromptGen.ts +2 -0
- package/src/Runner.ts +94 -61
package/dist/cli.mjs
CHANGED
|
@@ -140554,6 +140554,8 @@ ${prdNotes}`;
|
|
|
140554
140554
|
- Each task should be an atomic, committable piece of work.
|
|
140555
140555
|
Instead of creating tasks like "Refactor the authentication system", create
|
|
140556
140556
|
smaller tasks like "Implement OAuth2 login endpoint", "Add JWT token refresh mechanism", etc.
|
|
140557
|
+
- **Never** create a research task. You should do all the necessary research
|
|
140558
|
+
before creating the specification and tasks.
|
|
140557
140559
|
3. Add the new or updated tasks to the prd.yml file.
|
|
140558
140560
|
4. Wait until the tasks are saved, then setup task dependencies using the \`blockedBy\` field.
|
|
140559
140561
|
5. Start a subagent with a copy of this prompt, to review the plan and provide feedback or improvements.
|
|
@@ -140743,6 +140745,11 @@ const run = fnUntraced(function* (options) {
|
|
|
140743
140745
|
extendEnv: true,
|
|
140744
140746
|
env: cliAgent.env
|
|
140745
140747
|
})(template, ...args$1).pipe(exitCode);
|
|
140748
|
+
const execOutput = (template, ...args$1) => make$21({
|
|
140749
|
+
cwd: worktree.directory,
|
|
140750
|
+
extendEnv: true,
|
|
140751
|
+
env: cliAgent.env
|
|
140752
|
+
})(template, ...args$1).pipe(string, map$4((output) => output.trim()));
|
|
140746
140753
|
const execWithStallTimeout = fnUntraced(function* (command) {
|
|
140747
140754
|
let lastOutputAt = yield* now;
|
|
140748
140755
|
const stallTimeout = suspend$2(function loop() {
|
|
@@ -140768,47 +140775,58 @@ const run = fnUntraced(function* (options) {
|
|
|
140768
140775
|
return yield* handle.exitCode;
|
|
140769
140776
|
}, scoped$1);
|
|
140770
140777
|
if (isSome(options.targetBranch)) yield* exec`git checkout ${`origin/${options.targetBranch.value}`}`;
|
|
140771
|
-
const
|
|
140772
|
-
|
|
140773
|
-
|
|
140774
|
-
});
|
|
140775
|
-
yield* make$21(chooseCommand[0], chooseCommand.slice(1), {
|
|
140776
|
-
cwd: worktree.directory,
|
|
140777
|
-
extendEnv: true,
|
|
140778
|
-
env: cliAgent.env,
|
|
140779
|
-
stdout: "inherit",
|
|
140780
|
-
stderr: "inherit",
|
|
140781
|
-
stdin: "inherit"
|
|
140782
|
-
}).pipe(exitCode, timeoutOrElse({
|
|
140783
|
-
duration: options.stallTimeout,
|
|
140784
|
-
onTimeout: () => fail$4(new RunnerStalled())
|
|
140778
|
+
const currentBranch = execOutput`git branch --show-current`.pipe(map$4((branch) => {
|
|
140779
|
+
branch = branch.trim();
|
|
140780
|
+
return branch === "" ? null : branch;
|
|
140785
140781
|
}));
|
|
140786
|
-
|
|
140787
|
-
|
|
140788
|
-
|
|
140789
|
-
const exitCode$1 = yield* execWithStallTimeout(cliAgent.command({
|
|
140790
|
-
prompt: promptGen.prompt({
|
|
140791
|
-
taskId: task.id,
|
|
140792
|
-
targetBranch: getOrUndefined(options.targetBranch)
|
|
140793
|
-
}),
|
|
140794
|
-
prdFilePath: pathService.join(".lalph", "prd.yml")
|
|
140795
|
-
})).pipe(timeout(options.runTimeout), catchTag("TimeoutError", fnUntraced(function* (error$1) {
|
|
140796
|
-
yield* execWithStallTimeout(cliAgent.command({
|
|
140797
|
-
prompt: promptGen.promptTimeout({ taskId: task.id }),
|
|
140782
|
+
yield* gen(function* () {
|
|
140783
|
+
const chooseCommand = cliAgent.command({
|
|
140784
|
+
prompt: promptGen.promptChoose,
|
|
140798
140785
|
prdFilePath: pathService.join(".lalph", "prd.yml")
|
|
140786
|
+
});
|
|
140787
|
+
yield* make$21(chooseCommand[0], chooseCommand.slice(1), {
|
|
140788
|
+
cwd: worktree.directory,
|
|
140789
|
+
extendEnv: true,
|
|
140790
|
+
env: cliAgent.env,
|
|
140791
|
+
stdout: "inherit",
|
|
140792
|
+
stderr: "inherit",
|
|
140793
|
+
stdin: "inherit"
|
|
140794
|
+
}).pipe(exitCode, timeoutOrElse({
|
|
140795
|
+
duration: options.stallTimeout,
|
|
140796
|
+
onTimeout: () => fail$4(new RunnerStalled())
|
|
140799
140797
|
}));
|
|
140800
|
-
|
|
140801
|
-
|
|
140802
|
-
|
|
140803
|
-
|
|
140804
|
-
|
|
140805
|
-
|
|
140806
|
-
|
|
140807
|
-
|
|
140808
|
-
|
|
140809
|
-
|
|
140810
|
-
|
|
140811
|
-
|
|
140798
|
+
const taskJson = yield* fs.readFileString(pathService.join(worktree.directory, ".lalph", "task.json"));
|
|
140799
|
+
const task = yield* decodeEffect(ChosenTask)(taskJson);
|
|
140800
|
+
yield* completeWith(options.startedDeferred, void_$1);
|
|
140801
|
+
const exitCode$1 = yield* execWithStallTimeout(cliAgent.command({
|
|
140802
|
+
prompt: promptGen.prompt({
|
|
140803
|
+
taskId: task.id,
|
|
140804
|
+
targetBranch: getOrUndefined(options.targetBranch)
|
|
140805
|
+
}),
|
|
140806
|
+
prdFilePath: pathService.join(".lalph", "prd.yml")
|
|
140807
|
+
})).pipe(timeout(options.runTimeout), catchTag("TimeoutError", fnUntraced(function* (error$1) {
|
|
140808
|
+
yield* execWithStallTimeout(cliAgent.command({
|
|
140809
|
+
prompt: promptGen.promptTimeout({ taskId: task.id }),
|
|
140810
|
+
prdFilePath: pathService.join(".lalph", "prd.yml")
|
|
140811
|
+
}));
|
|
140812
|
+
return yield* error$1;
|
|
140813
|
+
})));
|
|
140814
|
+
yield* log$1(`Agent exited with code: ${exitCode$1}`);
|
|
140815
|
+
const prs = yield* prd.mergableGithubPrs;
|
|
140816
|
+
if (prs.length === 0) yield* prd.maybeRevertIssue({
|
|
140817
|
+
...task,
|
|
140818
|
+
issueId: task.id
|
|
140819
|
+
});
|
|
140820
|
+
else if (options.autoMerge) for (const pr of prs) {
|
|
140821
|
+
if (isSome(options.targetBranch)) yield* exec`gh pr edit ${pr.prNumber} --base ${options.targetBranch.value}`;
|
|
140822
|
+
if ((yield* exec`gh pr merge ${pr.prNumber} -sd`) !== 0) yield* prd.flagUnmergable({ issueId: pr.issueId });
|
|
140823
|
+
}
|
|
140824
|
+
}).pipe(ensuring(gen(function* () {
|
|
140825
|
+
const currentBranchName = yield* currentBranch;
|
|
140826
|
+
if (!currentBranchName) return;
|
|
140827
|
+
yield* exec`git checkout --detach ${currentBranchName}`;
|
|
140828
|
+
yield* exec`git branch -D ${currentBranchName}`;
|
|
140829
|
+
}).pipe(ignore)));
|
|
140812
140830
|
}, onError(fnUntraced(function* () {
|
|
140813
140831
|
const prd = yield* Prd;
|
|
140814
140832
|
yield* ignore(prd.revertStateIds);
|
package/package.json
CHANGED
package/src/PromptGen.ts
CHANGED
|
@@ -182,6 +182,8 @@ ${prdNotes}`
|
|
|
182
182
|
- Each task should be an atomic, committable piece of work.
|
|
183
183
|
Instead of creating tasks like "Refactor the authentication system", create
|
|
184
184
|
smaller tasks like "Implement OAuth2 login endpoint", "Add JWT token refresh mechanism", etc.
|
|
185
|
+
- **Never** create a research task. You should do all the necessary research
|
|
186
|
+
before creating the specification and tasks.
|
|
185
187
|
3. Add the new or updated tasks to the prd.yml file.
|
|
186
188
|
4. Wait until the tasks are saved, then setup task dependencies using the \`blockedBy\` field.
|
|
187
189
|
5. Start a subagent with a copy of this prompt, to review the plan and provide feedback or improvements.
|
package/src/Runner.ts
CHANGED
|
@@ -41,6 +41,19 @@ export const run = Effect.fnUntraced(
|
|
|
41
41
|
env: cliAgent.env,
|
|
42
42
|
})(template, ...args).pipe(ChildProcess.exitCode)
|
|
43
43
|
|
|
44
|
+
const execOutput = (
|
|
45
|
+
template: TemplateStringsArray,
|
|
46
|
+
...args: Array<string | number | boolean>
|
|
47
|
+
) =>
|
|
48
|
+
ChildProcess.make({
|
|
49
|
+
cwd: worktree.directory,
|
|
50
|
+
extendEnv: true,
|
|
51
|
+
env: cliAgent.env,
|
|
52
|
+
})(template, ...args).pipe(
|
|
53
|
+
ChildProcess.string,
|
|
54
|
+
Effect.map((output) => output.trim()),
|
|
55
|
+
)
|
|
56
|
+
|
|
44
57
|
const execWithStallTimeout = Effect.fnUntraced(function* (
|
|
45
58
|
command: ReadonlyArray<string>,
|
|
46
59
|
) {
|
|
@@ -88,77 +101,97 @@ export const run = Effect.fnUntraced(
|
|
|
88
101
|
yield* exec`git checkout ${`origin/${options.targetBranch.value}`}`
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
yield* ChildProcess.make(chooseCommand[0]!, chooseCommand.slice(1), {
|
|
97
|
-
cwd: worktree.directory,
|
|
98
|
-
extendEnv: true,
|
|
99
|
-
env: cliAgent.env,
|
|
100
|
-
stdout: "inherit",
|
|
101
|
-
stderr: "inherit",
|
|
102
|
-
stdin: "inherit",
|
|
103
|
-
}).pipe(
|
|
104
|
-
ChildProcess.exitCode,
|
|
105
|
-
Effect.timeoutOrElse({
|
|
106
|
-
duration: options.stallTimeout,
|
|
107
|
-
onTimeout: () => Effect.fail(new RunnerStalled()),
|
|
104
|
+
const currentBranch = execOutput`git branch --show-current`.pipe(
|
|
105
|
+
Effect.map((branch) => {
|
|
106
|
+
branch = branch.trim()
|
|
107
|
+
return branch === "" ? null : branch
|
|
108
108
|
}),
|
|
109
109
|
)
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
yield* Deferred.completeWith(options.startedDeferred, Effect.void)
|
|
111
|
+
yield* Effect.gen(function* () {
|
|
112
|
+
const chooseCommand = cliAgent.command({
|
|
113
|
+
prompt: promptGen.promptChoose,
|
|
114
|
+
prdFilePath: pathService.join(".lalph", "prd.yml"),
|
|
115
|
+
})
|
|
117
116
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
Effect.fnUntraced(function* (error) {
|
|
131
|
-
const timeoutCommand = cliAgent.command({
|
|
132
|
-
prompt: promptGen.promptTimeout({
|
|
133
|
-
taskId: task.id,
|
|
134
|
-
}),
|
|
135
|
-
prdFilePath: pathService.join(".lalph", "prd.yml"),
|
|
136
|
-
})
|
|
137
|
-
yield* execWithStallTimeout(timeoutCommand)
|
|
138
|
-
return yield* error
|
|
117
|
+
yield* ChildProcess.make(chooseCommand[0]!, chooseCommand.slice(1), {
|
|
118
|
+
cwd: worktree.directory,
|
|
119
|
+
extendEnv: true,
|
|
120
|
+
env: cliAgent.env,
|
|
121
|
+
stdout: "inherit",
|
|
122
|
+
stderr: "inherit",
|
|
123
|
+
stdin: "inherit",
|
|
124
|
+
}).pipe(
|
|
125
|
+
ChildProcess.exitCode,
|
|
126
|
+
Effect.timeoutOrElse({
|
|
127
|
+
duration: options.stallTimeout,
|
|
128
|
+
onTimeout: () => Effect.fail(new RunnerStalled()),
|
|
139
129
|
}),
|
|
140
|
-
)
|
|
141
|
-
)
|
|
142
|
-
yield* Effect.log(`Agent exited with code: ${exitCode}`)
|
|
130
|
+
)
|
|
143
131
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
132
|
+
const taskJson = yield* fs.readFileString(
|
|
133
|
+
pathService.join(worktree.directory, ".lalph", "task.json"),
|
|
134
|
+
)
|
|
135
|
+
const task = yield* Schema.decodeEffect(ChosenTask)(taskJson)
|
|
136
|
+
|
|
137
|
+
yield* Deferred.completeWith(options.startedDeferred, Effect.void)
|
|
138
|
+
|
|
139
|
+
const cliCommand = cliAgent.command({
|
|
140
|
+
prompt: promptGen.prompt({
|
|
141
|
+
taskId: task.id,
|
|
142
|
+
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
143
|
+
}),
|
|
144
|
+
prdFilePath: pathService.join(".lalph", "prd.yml"),
|
|
149
145
|
})
|
|
150
|
-
} else if (options.autoMerge) {
|
|
151
|
-
for (const pr of prs) {
|
|
152
|
-
if (Option.isSome(options.targetBranch)) {
|
|
153
|
-
yield* exec`gh pr edit ${pr.prNumber} --base ${options.targetBranch.value}`
|
|
154
|
-
}
|
|
155
146
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
147
|
+
const exitCode = yield* execWithStallTimeout(cliCommand).pipe(
|
|
148
|
+
Effect.timeout(options.runTimeout),
|
|
149
|
+
Effect.catchTag(
|
|
150
|
+
"TimeoutError",
|
|
151
|
+
Effect.fnUntraced(function* (error) {
|
|
152
|
+
const timeoutCommand = cliAgent.command({
|
|
153
|
+
prompt: promptGen.promptTimeout({
|
|
154
|
+
taskId: task.id,
|
|
155
|
+
}),
|
|
156
|
+
prdFilePath: pathService.join(".lalph", "prd.yml"),
|
|
157
|
+
})
|
|
158
|
+
yield* execWithStallTimeout(timeoutCommand)
|
|
159
|
+
return yield* error
|
|
160
|
+
}),
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
yield* Effect.log(`Agent exited with code: ${exitCode}`)
|
|
164
|
+
|
|
165
|
+
const prs = yield* prd.mergableGithubPrs
|
|
166
|
+
if (prs.length === 0) {
|
|
167
|
+
yield* prd.maybeRevertIssue({
|
|
168
|
+
...task,
|
|
169
|
+
issueId: task.id,
|
|
170
|
+
})
|
|
171
|
+
} else if (options.autoMerge) {
|
|
172
|
+
for (const pr of prs) {
|
|
173
|
+
if (Option.isSome(options.targetBranch)) {
|
|
174
|
+
yield* exec`gh pr edit ${pr.prNumber} --base ${options.targetBranch.value}`
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const exitCode = yield* exec`gh pr merge ${pr.prNumber} -sd`
|
|
178
|
+
if (exitCode !== 0) {
|
|
179
|
+
yield* prd.flagUnmergable({ issueId: pr.issueId })
|
|
180
|
+
}
|
|
159
181
|
}
|
|
160
182
|
}
|
|
161
|
-
}
|
|
183
|
+
}).pipe(
|
|
184
|
+
Effect.ensuring(
|
|
185
|
+
Effect.gen(function* () {
|
|
186
|
+
const currentBranchName = yield* currentBranch
|
|
187
|
+
if (!currentBranchName) return
|
|
188
|
+
// enter detached state
|
|
189
|
+
yield* exec`git checkout --detach ${currentBranchName}`
|
|
190
|
+
// delete the branch
|
|
191
|
+
yield* exec`git branch -D ${currentBranchName}`
|
|
192
|
+
}).pipe(Effect.ignore),
|
|
193
|
+
),
|
|
194
|
+
)
|
|
162
195
|
},
|
|
163
196
|
// on interrupt or error, revert any state changes made in the PRD
|
|
164
197
|
Effect.onError(
|