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 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 chooseCommand = cliAgent.command({
140772
- prompt: promptGen.promptChoose,
140773
- prdFilePath: pathService.join(".lalph", "prd.yml")
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
- const taskJson = yield* fs.readFileString(pathService.join(worktree.directory, ".lalph", "task.json"));
140787
- const task = yield* decodeEffect(ChosenTask)(taskJson);
140788
- yield* completeWith(options.startedDeferred, void_$1);
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
- return yield* error$1;
140801
- })));
140802
- yield* log$1(`Agent exited with code: ${exitCode$1}`);
140803
- const prs = yield* prd.mergableGithubPrs;
140804
- if (prs.length === 0) yield* prd.maybeRevertIssue({
140805
- ...task,
140806
- issueId: task.id
140807
- });
140808
- else if (options.autoMerge) for (const pr of prs) {
140809
- if (isSome(options.targetBranch)) yield* exec`gh pr edit ${pr.prNumber} --base ${options.targetBranch.value}`;
140810
- if ((yield* exec`gh pr merge ${pr.prNumber} -sd`) !== 0) yield* prd.flagUnmergable({ issueId: pr.issueId });
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lalph",
3
3
  "type": "module",
4
- "version": "0.1.36",
4
+ "version": "0.1.37",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
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 chooseCommand = cliAgent.command({
92
- prompt: promptGen.promptChoose,
93
- prdFilePath: pathService.join(".lalph", "prd.yml"),
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
- const taskJson = yield* fs.readFileString(
112
- pathService.join(worktree.directory, ".lalph", "task.json"),
113
- )
114
- const task = yield* Schema.decodeEffect(ChosenTask)(taskJson)
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
- const cliCommand = cliAgent.command({
119
- prompt: promptGen.prompt({
120
- taskId: task.id,
121
- targetBranch: Option.getOrUndefined(options.targetBranch),
122
- }),
123
- prdFilePath: pathService.join(".lalph", "prd.yml"),
124
- })
125
-
126
- const exitCode = yield* execWithStallTimeout(cliCommand).pipe(
127
- Effect.timeout(options.runTimeout),
128
- Effect.catchTag(
129
- "TimeoutError",
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
- const prs = yield* prd.mergableGithubPrs
145
- if (prs.length === 0) {
146
- yield* prd.maybeRevertIssue({
147
- ...task,
148
- issueId: task.id,
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
- const exitCode = yield* exec`gh pr merge ${pr.prNumber} -sd`
157
- if (exitCode !== 0) {
158
- yield* prd.flagUnmergable({ issueId: pr.issueId })
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(