lalph 0.3.137 → 0.3.139
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 +46125 -44180
- package/package.json +13 -14
- package/src/GitFlow.ts +14 -4
- package/src/Github/Cli.ts +40 -1
- package/src/Linear/TokenManager.ts +1 -0
- package/src/commands/root.ts +18 -9
- package/src/domain/CliAgent.ts +9 -2
- package/src/shared/git.ts +3 -1
- package/dist/cli.d.mts +0 -1
- package/dist/cli.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lalph",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.139",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"url": "https://github.com/tim-smart/lalph.git"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"better-sqlite3": "^12.10.0",
|
|
24
23
|
"tree-sitter": "^0.21.1",
|
|
25
24
|
"tree-sitter-javascript": "^0.23.1",
|
|
26
25
|
"tree-sitter-typescript": "^0.23.2"
|
|
@@ -37,23 +36,23 @@
|
|
|
37
36
|
"devDependencies": {
|
|
38
37
|
"@changesets/changelog-github": "^0.7.0",
|
|
39
38
|
"@changesets/cli": "^2.31.0",
|
|
40
|
-
"@effect/ai-openai": "4.0.0-beta.
|
|
41
|
-
"@effect/ai-openai-compat": "4.0.0-beta.
|
|
42
|
-
"@effect/language-service": "^0.86.
|
|
43
|
-
"@effect/platform-node": "4.0.0-beta.
|
|
44
|
-
"@linear/sdk": "^
|
|
39
|
+
"@effect/ai-openai": "4.0.0-beta.94",
|
|
40
|
+
"@effect/ai-openai-compat": "4.0.0-beta.94",
|
|
41
|
+
"@effect/language-service": "^0.86.4",
|
|
42
|
+
"@effect/platform-node": "4.0.0-beta.94",
|
|
43
|
+
"@linear/sdk": "^88.0.0",
|
|
45
44
|
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
|
|
46
45
|
"@octokit/types": "^16.0.0",
|
|
47
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
48
|
-
"clanka": "^0.2.
|
|
46
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
47
|
+
"clanka": "^0.2.69",
|
|
49
48
|
"concurrently": "^10.0.3",
|
|
50
|
-
"effect": "4.0.0-beta.
|
|
49
|
+
"effect": "4.0.0-beta.94",
|
|
51
50
|
"husky": "^9.1.7",
|
|
52
|
-
"lint-staged": "^17.0.
|
|
51
|
+
"lint-staged": "^17.0.8",
|
|
53
52
|
"octokit": "^5.0.5",
|
|
54
|
-
"oxlint": "^1.
|
|
55
|
-
"prettier": "^3.
|
|
56
|
-
"tsdown": "^0.22.
|
|
53
|
+
"oxlint": "^1.73.0",
|
|
54
|
+
"prettier": "^3.9.4",
|
|
55
|
+
"tsdown": "^0.22.3",
|
|
57
56
|
"typescript": "^6.0.3",
|
|
58
57
|
"yaml": "^2.9.0"
|
|
59
58
|
},
|
package/src/GitFlow.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { Atom } from "effect/unstable/reactivity"
|
|
|
8
8
|
import { parseBranch } from "./shared/git.ts"
|
|
9
9
|
import { AtomRegistry } from "effect/unstable/reactivity"
|
|
10
10
|
import { CurrentProjectId } from "./Settings.ts"
|
|
11
|
+
import type { PrdIssue } from "./domain/PrdIssue.ts"
|
|
11
12
|
|
|
12
13
|
// @effect-diagnostics-next-line leakingRequirements:off
|
|
13
14
|
export class GitFlow extends Context.Service<
|
|
@@ -130,8 +131,12 @@ export const GitFlowCommit = Layer.effect(
|
|
|
130
131
|
requiresGithubPr: false,
|
|
131
132
|
branch: `lalph/worker-${workerState.id}`,
|
|
132
133
|
|
|
133
|
-
setupInstructions: () =>
|
|
134
|
-
|
|
134
|
+
setupInstructions: ({ githubPrNumber }) =>
|
|
135
|
+
githubPrNumber
|
|
136
|
+
? `You are already on a new branch for this task. Github PR #${githubPrNumber} has been detected.
|
|
137
|
+
- **REVIEW ALL FEEDBACK** in the .lalph/feedback.md file.
|
|
138
|
+
- Do not checkout any other branches.`
|
|
139
|
+
: `You are already on a new branch for this task. You do not need to checkout any other branches.`,
|
|
135
140
|
|
|
136
141
|
commitInstructions: (
|
|
137
142
|
options,
|
|
@@ -185,13 +190,18 @@ But you **do not** need to git push your changes or switch branches.
|
|
|
185
190
|
const source = yield* IssueSource
|
|
186
191
|
const projectId = yield* CurrentProjectId
|
|
187
192
|
const issue = yield* source.findById(projectId, options.issueId)
|
|
188
|
-
|
|
193
|
+
let nextStatus: PrdIssue["state"] = "done"
|
|
194
|
+
if (!issue) {
|
|
195
|
+
return
|
|
196
|
+
} else if (issue.state === "in-progress") {
|
|
197
|
+
nextStatus = "todo"
|
|
198
|
+
} else if (issue.state !== "in-review") {
|
|
189
199
|
return
|
|
190
200
|
}
|
|
191
201
|
yield* source.updateIssue({
|
|
192
202
|
projectId,
|
|
193
203
|
issueId: options.issueId,
|
|
194
|
-
state:
|
|
204
|
+
state: nextStatus,
|
|
195
205
|
})
|
|
196
206
|
}),
|
|
197
207
|
})
|
package/src/Github/Cli.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
GithubPullRequestData,
|
|
15
15
|
ReviewComment,
|
|
16
16
|
} from "../domain/GithubComment.ts"
|
|
17
|
+
import { parseBranch } from "../shared/git.ts"
|
|
17
18
|
|
|
18
19
|
export class GithubCli extends Context.Service<GithubCli>()(
|
|
19
20
|
"lalph/Github/Cli",
|
|
@@ -61,6 +62,28 @@ export class GithubCli extends Context.Service<GithubCli>()(
|
|
|
61
62
|
),
|
|
62
63
|
)
|
|
63
64
|
|
|
65
|
+
const openPrForBranch = (targetBranch: string) => {
|
|
66
|
+
const branch = parseBranch(targetBranch).branch
|
|
67
|
+
return ChildProcess.make`gh pr list --head ${branch} --state open --limit 1 --json number,state`.pipe(
|
|
68
|
+
spawner.string,
|
|
69
|
+
Effect.flatMap(Schema.decodeEffect(OpenPullRequestsFromJson)),
|
|
70
|
+
Effect.option,
|
|
71
|
+
Effect.map(
|
|
72
|
+
Option.match({
|
|
73
|
+
onNone: () => Option.none<OpenPullRequest>(),
|
|
74
|
+
onSome: (prs) =>
|
|
75
|
+
prs.length > 0
|
|
76
|
+
? Option.some(prs[0]!)
|
|
77
|
+
: Option.none<OpenPullRequest>(),
|
|
78
|
+
}),
|
|
79
|
+
),
|
|
80
|
+
Effect.provideService(
|
|
81
|
+
ChildProcessSpawner.ChildProcessSpawner,
|
|
82
|
+
spawner,
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
64
87
|
const prFeedbackMd = (pr: number) =>
|
|
65
88
|
reviewComments(pr).pipe(
|
|
66
89
|
Effect.map(({ comments, reviewThreads, reviews }) => {
|
|
@@ -130,7 +153,13 @@ ${generalCommentsXml}
|
|
|
130
153
|
}),
|
|
131
154
|
)
|
|
132
155
|
|
|
133
|
-
return {
|
|
156
|
+
return {
|
|
157
|
+
owner,
|
|
158
|
+
repo,
|
|
159
|
+
reviewComments,
|
|
160
|
+
openPrForBranch,
|
|
161
|
+
prFeedbackMd,
|
|
162
|
+
} as const
|
|
134
163
|
}),
|
|
135
164
|
},
|
|
136
165
|
) {
|
|
@@ -181,6 +210,16 @@ const renderGeneralComment = (
|
|
|
181
210
|
|
|
182
211
|
const PullRequestDataFromJson = Schema.fromJsonString(GithubPullRequestData)
|
|
183
212
|
|
|
213
|
+
const OpenPullRequest = Schema.Struct({
|
|
214
|
+
number: Schema.Finite,
|
|
215
|
+
state: Schema.String,
|
|
216
|
+
})
|
|
217
|
+
type OpenPullRequest = Schema.Schema.Type<typeof OpenPullRequest>
|
|
218
|
+
|
|
219
|
+
const OpenPullRequestsFromJson = Schema.fromJsonString(
|
|
220
|
+
Schema.Array(OpenPullRequest),
|
|
221
|
+
)
|
|
222
|
+
|
|
184
223
|
const githubReviewCommentsQuery = `
|
|
185
224
|
query FetchPRComments($owner: String!, $repo: String!, $pr: Int!) {
|
|
186
225
|
repository(owner: $owner, name: $repo) {
|
package/src/commands/root.ts
CHANGED
|
@@ -176,17 +176,26 @@ const run = Effect.fnUntraced(
|
|
|
176
176
|
|
|
177
177
|
yield* Deferred.completeWith(options.startedDeferred, Effect.void)
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
yield* fs.writeFileString(
|
|
183
|
-
pathService.join(worktree.directory, ".lalph", "feedback.md"),
|
|
184
|
-
feedback,
|
|
185
|
-
)
|
|
179
|
+
let githubPrNumber = chosenTask.githubPrNumber ?? undefined
|
|
180
|
+
if (gitFlow.requiresGithubPr && githubPrNumber) {
|
|
181
|
+
yield* worktree.exec`gh pr checkout ${githubPrNumber}`
|
|
186
182
|
} else if (gitFlow.requiresGithubPr) {
|
|
187
183
|
const branchName = `lalph/${taskId.replace(/#/g, "").replace(/[^a-zA-Z0-9-_]/g, "-")}`
|
|
188
184
|
yield* worktree.exec`git branch -D ${branchName}`
|
|
189
185
|
yield* worktree.exec`git checkout -b ${branchName}`
|
|
186
|
+
} else if (Option.isSome(options.targetBranch)) {
|
|
187
|
+
const prState = yield* gh.openPrForBranch(options.targetBranch.value)
|
|
188
|
+
if (Option.isSome(prState) && prState.value.state === "OPEN") {
|
|
189
|
+
githubPrNumber = prState.value.number
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (githubPrNumber !== undefined) {
|
|
194
|
+
const feedback = yield* gh.prFeedbackMd(githubPrNumber)
|
|
195
|
+
yield* fs.writeFileString(
|
|
196
|
+
pathService.join(worktree.directory, ".lalph", "feedback.md"),
|
|
197
|
+
feedback,
|
|
198
|
+
)
|
|
190
199
|
}
|
|
191
200
|
|
|
192
201
|
const taskPreset = Option.getOrElse(
|
|
@@ -232,14 +241,14 @@ const run = Effect.fnUntraced(
|
|
|
232
241
|
specsDirectory: options.specsDirectory,
|
|
233
242
|
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
234
243
|
task: chosenTask.prd,
|
|
235
|
-
githubPrNumber
|
|
244
|
+
githubPrNumber,
|
|
236
245
|
gitFlow,
|
|
237
246
|
})
|
|
238
247
|
: promptGen.promptClanka({
|
|
239
248
|
specsDirectory: options.specsDirectory,
|
|
240
249
|
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
241
250
|
task: chosenTask.prd,
|
|
242
|
-
githubPrNumber
|
|
251
|
+
githubPrNumber,
|
|
243
252
|
gitFlow,
|
|
244
253
|
})
|
|
245
254
|
|
package/src/domain/CliAgent.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Data,
|
|
3
|
+
Duration,
|
|
3
4
|
PlatformError,
|
|
4
5
|
Schema,
|
|
5
6
|
SchemaTransformation,
|
|
@@ -33,6 +34,12 @@ const escapeLeadingHyphen = (text: string) => {
|
|
|
33
34
|
return text
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
const claudeInterruptOptions = {
|
|
38
|
+
stdin: "ignore",
|
|
39
|
+
killSignal: "SIGINT",
|
|
40
|
+
forceKillAfter: Duration.seconds(2),
|
|
41
|
+
} as const
|
|
42
|
+
|
|
36
43
|
const clanka = new CliAgent({
|
|
37
44
|
id: "clanka",
|
|
38
45
|
name: "clanka",
|
|
@@ -137,7 +144,7 @@ ${prompt}`
|
|
|
137
144
|
{
|
|
138
145
|
stdout: "pipe",
|
|
139
146
|
stderr: "pipe",
|
|
140
|
-
|
|
147
|
+
...claudeInterruptOptions,
|
|
141
148
|
},
|
|
142
149
|
),
|
|
143
150
|
outputTransformer: claudeOutputTransformer,
|
|
@@ -153,7 +160,7 @@ ${prompt}`,
|
|
|
153
160
|
{
|
|
154
161
|
stdout: "inherit",
|
|
155
162
|
stderr: "inherit",
|
|
156
|
-
|
|
163
|
+
...claudeInterruptOptions,
|
|
157
164
|
},
|
|
158
165
|
),
|
|
159
166
|
})
|
package/src/shared/git.ts
CHANGED
|
@@ -8,7 +8,9 @@ export const parseBranch = (
|
|
|
8
8
|
if (!ref.startsWith("origin/") && !ref.startsWith("upstream/")) {
|
|
9
9
|
return { remote: "origin", branch: ref, branchWithRemote: `origin/${ref}` }
|
|
10
10
|
}
|
|
11
|
-
const
|
|
11
|
+
const separator = ref.indexOf("/")
|
|
12
|
+
const remote = ref.slice(0, separator)
|
|
13
|
+
const branch = ref.slice(separator + 1)
|
|
12
14
|
const branchWithRemote = `${remote}/${branch}`
|
|
13
15
|
return { remote, branch, branchWithRemote } as const
|
|
14
16
|
}
|
package/dist/cli.d.mts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|