lalph 0.3.32 → 0.3.34
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/README.md +2 -0
- package/dist/cli.mjs +1572 -1295
- package/package.json +3 -3
- package/src/Agents/planner.ts +3 -2
- package/src/Editor.ts +2 -2
- package/src/GitFlow.ts +10 -0
- package/src/Github/Cli.ts +2 -2
- package/src/Github.ts +89 -1
- package/src/Worktree.ts +12 -7
- package/src/cli.ts +4 -8
- package/src/commands/agents.ts +1 -7
- package/src/commands/edit.ts +1 -7
- package/src/commands/issue.ts +1 -7
- package/src/commands/plan/tasks.ts +2 -2
- package/src/commands/plan.ts +5 -4
- package/src/commands/projects.ts +1 -5
- package/src/commands/sh.ts +3 -2
- package/src/shared/config.ts +1 -1
- package/src/shared/stream.ts +1 -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.34",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"@changesets/changelog-github": "^0.5.2",
|
|
24
24
|
"@changesets/cli": "^2.29.8",
|
|
25
25
|
"@effect/language-service": "^0.75.1",
|
|
26
|
-
"@effect/platform-node": "4.0.0-beta.
|
|
26
|
+
"@effect/platform-node": "4.0.0-beta.21",
|
|
27
27
|
"@linear/sdk": "^75.0.0",
|
|
28
28
|
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
|
|
29
29
|
"@octokit/types": "^16.0.0",
|
|
30
30
|
"@typescript/native-preview": "7.0.0-dev.20260219.1",
|
|
31
31
|
"concurrently": "^9.2.1",
|
|
32
|
-
"effect": "4.0.0-beta.
|
|
32
|
+
"effect": "4.0.0-beta.21",
|
|
33
33
|
"husky": "^9.1.7",
|
|
34
34
|
"lint-staged": "^16.2.7",
|
|
35
35
|
"octokit": "^5.0.5",
|
package/src/Agents/planner.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Effect, Path, pipe } from "effect"
|
|
2
2
|
import { PromptGen } from "../PromptGen.ts"
|
|
3
|
-
import { ChildProcess } from "effect/unstable/process"
|
|
3
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
|
4
4
|
import { Worktree } from "../Worktree.ts"
|
|
5
5
|
import type { CliAgentPreset } from "../domain/CliAgentPreset.ts"
|
|
6
6
|
|
|
@@ -13,6 +13,7 @@ export const agentPlanner = Effect.fnUntraced(function* (options: {
|
|
|
13
13
|
const pathService = yield* Path.Path
|
|
14
14
|
const worktree = yield* Worktree
|
|
15
15
|
const promptGen = yield* PromptGen
|
|
16
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
16
17
|
|
|
17
18
|
yield* pipe(
|
|
18
19
|
options.preset.cliAgent.commandPlan({
|
|
@@ -22,6 +23,6 @@ export const agentPlanner = Effect.fnUntraced(function* (options: {
|
|
|
22
23
|
}),
|
|
23
24
|
ChildProcess.setCwd(worktree.directory),
|
|
24
25
|
options.preset.withCommandPrefix,
|
|
25
|
-
|
|
26
|
+
spawner.exitCode,
|
|
26
27
|
)
|
|
27
28
|
})
|
package/src/Editor.ts
CHANGED
|
@@ -15,7 +15,7 @@ export class Editor extends ServiceMap.Service<Editor>()("lalph/Editor", {
|
|
|
15
15
|
stdout: "inherit",
|
|
16
16
|
stderr: "inherit",
|
|
17
17
|
}).pipe(
|
|
18
|
-
|
|
18
|
+
spawner.exitCode,
|
|
19
19
|
Effect.provideService(ChildProcessSpawner.ChildProcessSpawner, spawner),
|
|
20
20
|
Effect.orDie,
|
|
21
21
|
)
|
|
@@ -41,7 +41,7 @@ export class Editor extends ServiceMap.Service<Editor>()("lalph/Editor", {
|
|
|
41
41
|
stdout: "inherit",
|
|
42
42
|
stderr: "inherit",
|
|
43
43
|
},
|
|
44
|
-
).pipe(
|
|
44
|
+
).pipe(spawner.exitCode)
|
|
45
45
|
|
|
46
46
|
if (exitCode !== 0) {
|
|
47
47
|
return yield* new Cause.NoSuchElementError()
|
package/src/GitFlow.ts
CHANGED
|
@@ -81,6 +81,8 @@ After making any changes, commit and push them to the same pull request.
|
|
|
81
81
|
postWork: () => Effect.void,
|
|
82
82
|
autoMerge: Effect.fnUntraced(function* (options) {
|
|
83
83
|
const prd = yield* Prd
|
|
84
|
+
const source = yield* IssueSource
|
|
85
|
+
const projectId = yield* CurrentProjectId
|
|
84
86
|
const worktree = options.worktree
|
|
85
87
|
|
|
86
88
|
let prState = (yield* worktree.viewPrState()).pipe(
|
|
@@ -101,6 +103,14 @@ After making any changes, commit and push them to the same pull request.
|
|
|
101
103
|
prState = yield* worktree.viewPrState(prState.value.number)
|
|
102
104
|
yield* Effect.log("PR state after merge", prState)
|
|
103
105
|
if (Option.isSome(prState) && prState.value.state === "MERGED") {
|
|
106
|
+
const issue = yield* prd.findById(options.issueId)
|
|
107
|
+
if (issue && issue.state !== "done") {
|
|
108
|
+
yield* source.updateIssue({
|
|
109
|
+
projectId,
|
|
110
|
+
issueId: options.issueId,
|
|
111
|
+
state: "done",
|
|
112
|
+
})
|
|
113
|
+
}
|
|
104
114
|
return
|
|
105
115
|
}
|
|
106
116
|
yield* Effect.log("Flagging unmergable PR")
|
package/src/Github/Cli.ts
CHANGED
|
@@ -23,7 +23,7 @@ export class GithubCli extends ServiceMap.Service<GithubCli>()(
|
|
|
23
23
|
|
|
24
24
|
const nameWithOwner =
|
|
25
25
|
yield* ChildProcess.make`gh repo view --json nameWithOwner -q ${".nameWithOwner"}`.pipe(
|
|
26
|
-
|
|
26
|
+
spawner.string,
|
|
27
27
|
Effect.option,
|
|
28
28
|
Effect.flatMap(
|
|
29
29
|
flow(
|
|
@@ -40,7 +40,7 @@ export class GithubCli extends ServiceMap.Service<GithubCli>()(
|
|
|
40
40
|
|
|
41
41
|
const reviewComments = (pr: number) =>
|
|
42
42
|
ChildProcess.make`gh api graphql -f owner=${owner} -f repo=${repo} -F pr=${pr} -f query=${githubReviewCommentsQuery}`.pipe(
|
|
43
|
-
|
|
43
|
+
spawner.string,
|
|
44
44
|
Effect.flatMap(Schema.decodeEffect(PullRequestDataFromJson)),
|
|
45
45
|
Effect.map((data) => {
|
|
46
46
|
const comments =
|
package/src/Github.ts
CHANGED
|
@@ -33,6 +33,7 @@ export class GithubError extends Data.TaggedError("GithubError")<{
|
|
|
33
33
|
|
|
34
34
|
export type GithubApi = Api["rest"]
|
|
35
35
|
export type GithubResponse<A> = OctokitResponse<A>
|
|
36
|
+
type GithubResponseHeaders = OctokitResponse<unknown>["headers"]
|
|
36
37
|
|
|
37
38
|
export interface GithubService {
|
|
38
39
|
readonly request: <A>(
|
|
@@ -46,6 +47,13 @@ export interface GithubService {
|
|
|
46
47
|
) => Stream.Stream<A, GithubError, never>
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
type CachedGetResponse = {
|
|
51
|
+
readonly etag: string
|
|
52
|
+
readonly data: unknown
|
|
53
|
+
readonly headers: GithubResponseHeaders
|
|
54
|
+
readonly url: string
|
|
55
|
+
}
|
|
56
|
+
|
|
49
57
|
export class Github extends ServiceMap.Service<Github, GithubService>()(
|
|
50
58
|
"lalph/Github",
|
|
51
59
|
{
|
|
@@ -53,7 +61,54 @@ export class Github extends ServiceMap.Service<Github, GithubService>()(
|
|
|
53
61
|
const tokens = yield* TokenManager
|
|
54
62
|
const clients = yield* RcMap.make({
|
|
55
63
|
lookup: (token: string) =>
|
|
56
|
-
Effect.
|
|
64
|
+
Effect.sync(() => {
|
|
65
|
+
const octokit = new Octokit({ auth: token })
|
|
66
|
+
const etagCache = new Map<string, CachedGetResponse>()
|
|
67
|
+
|
|
68
|
+
octokit.hook.wrap("request", async (request, options) => {
|
|
69
|
+
if (requestMethod(options) !== "GET") {
|
|
70
|
+
return request(options)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const key = requestCacheKey(options)
|
|
74
|
+
const cached = etagCache.get(key)
|
|
75
|
+
const ifNoneMatchHeader = cached
|
|
76
|
+
? {
|
|
77
|
+
...options.headers,
|
|
78
|
+
"if-none-match": cached.etag,
|
|
79
|
+
}
|
|
80
|
+
: options.headers
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const response = await request({
|
|
84
|
+
...options,
|
|
85
|
+
headers: ifNoneMatchHeader,
|
|
86
|
+
})
|
|
87
|
+
const etag = etagHeaderValue(response.headers)
|
|
88
|
+
if (etag !== undefined) {
|
|
89
|
+
etagCache.set(key, {
|
|
90
|
+
etag,
|
|
91
|
+
data: response.data,
|
|
92
|
+
headers: response.headers,
|
|
93
|
+
url: response.url,
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
return response
|
|
97
|
+
} catch (cause) {
|
|
98
|
+
if (isNotModifiedError(cause) && cached) {
|
|
99
|
+
return {
|
|
100
|
+
status: 200,
|
|
101
|
+
headers: cached.headers,
|
|
102
|
+
url: cached.url,
|
|
103
|
+
data: cached.data,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
throw cause
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
return octokit.rest
|
|
111
|
+
}),
|
|
57
112
|
idleTimeToLive: "1 minute",
|
|
58
113
|
})
|
|
59
114
|
const getClient = tokens.get.pipe(
|
|
@@ -620,3 +675,36 @@ const maybeNextPage = (page: number, linkHeader?: string) =>
|
|
|
620
675
|
Option.filter((_) => _.includes(`rel="next"`)),
|
|
621
676
|
Option.as(page + 1),
|
|
622
677
|
)
|
|
678
|
+
|
|
679
|
+
const requestMethod = (options: { readonly method?: string }) =>
|
|
680
|
+
options.method?.toUpperCase() ?? "GET"
|
|
681
|
+
|
|
682
|
+
const requestCacheKey = (options: {
|
|
683
|
+
readonly method?: string
|
|
684
|
+
readonly url?: string
|
|
685
|
+
readonly headers?: Record<string, unknown>
|
|
686
|
+
}) => {
|
|
687
|
+
const method = requestMethod(options)
|
|
688
|
+
const url = options.url ?? ""
|
|
689
|
+
const acceptHeader = options.headers?.accept
|
|
690
|
+
const accept = typeof acceptHeader === "string" ? acceptHeader : ""
|
|
691
|
+
return `${method}:${url}:${accept}`
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const etagHeaderValue = (
|
|
695
|
+
headers: GithubResponseHeaders,
|
|
696
|
+
): string | undefined => {
|
|
697
|
+
const etag = headers.etag
|
|
698
|
+
if (typeof etag === "string" && etag.length > 0) {
|
|
699
|
+
return etag
|
|
700
|
+
}
|
|
701
|
+
return undefined
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const isNotModifiedError = (
|
|
705
|
+
cause: unknown,
|
|
706
|
+
): cause is { readonly status: number } =>
|
|
707
|
+
typeof cause === "object" &&
|
|
708
|
+
cause !== null &&
|
|
709
|
+
"status" in cause &&
|
|
710
|
+
(cause as { readonly status: unknown }).status === 304
|
package/src/Worktree.ts
CHANGED
|
@@ -28,6 +28,7 @@ export class Worktree extends ServiceMap.Service<Worktree>()("lalph/Worktree", {
|
|
|
28
28
|
make: Effect.gen(function* () {
|
|
29
29
|
const fs = yield* FileSystem.FileSystem
|
|
30
30
|
const pathService = yield* Path.Path
|
|
31
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
31
32
|
|
|
32
33
|
const inExisting = yield* fs.exists(pathService.join(".lalph", "prd.yml"))
|
|
33
34
|
if (inExisting) {
|
|
@@ -44,13 +45,14 @@ export class Worktree extends ServiceMap.Service<Worktree>()("lalph/Worktree", {
|
|
|
44
45
|
yield* Effect.addFinalizer(
|
|
45
46
|
Effect.fnUntraced(function* () {
|
|
46
47
|
yield* execIgnore(
|
|
48
|
+
spawner,
|
|
47
49
|
ChildProcess.make`git worktree remove --force ${directory}`,
|
|
48
50
|
)
|
|
49
51
|
}),
|
|
50
52
|
)
|
|
51
53
|
|
|
52
54
|
yield* ChildProcess.make`git worktree add ${directory} -d HEAD`.pipe(
|
|
53
|
-
|
|
55
|
+
spawner.exitCode,
|
|
54
56
|
)
|
|
55
57
|
|
|
56
58
|
yield* fs.makeDirectory(pathService.join(directory, ".lalph"), {
|
|
@@ -86,8 +88,10 @@ export class Worktree extends ServiceMap.Service<Worktree>()("lalph/Worktree", {
|
|
|
86
88
|
)
|
|
87
89
|
}
|
|
88
90
|
|
|
89
|
-
const execIgnore = (
|
|
90
|
-
|
|
91
|
+
const execIgnore = (
|
|
92
|
+
spawner: ChildProcessSpawner.ChildProcessSpawner["Service"],
|
|
93
|
+
command: ChildProcess.Command,
|
|
94
|
+
) => command.pipe(spawner.exitCode, Effect.catchCause(Effect.logWarning))
|
|
91
95
|
|
|
92
96
|
const seedSetupScript = Effect.fnUntraced(function* (setupPath: string) {
|
|
93
97
|
const fs = yield* FileSystem.FileSystem
|
|
@@ -111,6 +115,7 @@ const setupWorktree = Effect.fnUntraced(function* (options: {
|
|
|
111
115
|
...args: Array<string | number | boolean>
|
|
112
116
|
) => Effect.Effect<ChildProcessSpawner.ExitCode, PlatformError.PlatformError>
|
|
113
117
|
}) {
|
|
118
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
114
119
|
const fs = yield* FileSystem.FileSystem
|
|
115
120
|
const pathService = yield* Path.Path
|
|
116
121
|
const targetBranch = yield* getTargetBranch
|
|
@@ -142,7 +147,7 @@ const setupWorktree = Effect.fnUntraced(function* (options: {
|
|
|
142
147
|
yield* ChildProcess.make({
|
|
143
148
|
cwd: options.directory,
|
|
144
149
|
shell: process.env.SHELL ?? true,
|
|
145
|
-
})`${setupPath}`.pipe(
|
|
150
|
+
})`${setupPath}`.pipe(spawner.exitCode)
|
|
146
151
|
})
|
|
147
152
|
|
|
148
153
|
const getTargetBranch = Effect.gen(function* () {
|
|
@@ -178,7 +183,7 @@ const makeExecHelpers = Effect.fnUntraced(function* (options: {
|
|
|
178
183
|
cwd: options.directory,
|
|
179
184
|
stderr: "inherit",
|
|
180
185
|
stdout: "inherit",
|
|
181
|
-
})(template, ...args).pipe(
|
|
186
|
+
})(template, ...args).pipe(spawner.exitCode, provide)
|
|
182
187
|
|
|
183
188
|
const execString = (
|
|
184
189
|
template: TemplateStringsArray,
|
|
@@ -186,7 +191,7 @@ const makeExecHelpers = Effect.fnUntraced(function* (options: {
|
|
|
186
191
|
) =>
|
|
187
192
|
ChildProcess.make({
|
|
188
193
|
cwd: options.directory,
|
|
189
|
-
})(template, ...args).pipe(
|
|
194
|
+
})(template, ...args).pipe(spawner.string, provide)
|
|
190
195
|
|
|
191
196
|
const viewPrState = (prNumber?: number) =>
|
|
192
197
|
execString`gh pr view ${prNumber ? prNumber : ""} --json number,state`.pipe(
|
|
@@ -298,7 +303,7 @@ const makeExecHelpers = Effect.fnUntraced(function* (options: {
|
|
|
298
303
|
ChildProcess.make({
|
|
299
304
|
cwd: dir,
|
|
300
305
|
})`git branch --show-current`.pipe(
|
|
301
|
-
|
|
306
|
+
spawner.string,
|
|
302
307
|
provide,
|
|
303
308
|
Effect.flatMap((output) =>
|
|
304
309
|
Option.some(output.trim()).pipe(
|
package/src/cli.ts
CHANGED
|
@@ -6,17 +6,17 @@ import { NodeRuntime } from "@effect/platform-node"
|
|
|
6
6
|
import { Settings } from "./Settings.ts"
|
|
7
7
|
import { commandRoot } from "./commands/root.ts"
|
|
8
8
|
import { commandPlan } from "./commands/plan.ts"
|
|
9
|
-
import { commandIssue
|
|
10
|
-
import { commandEdit
|
|
9
|
+
import { commandIssue } from "./commands/issue.ts"
|
|
10
|
+
import { commandEdit } from "./commands/edit.ts"
|
|
11
11
|
import { commandSource } from "./commands/source.ts"
|
|
12
12
|
import PackageJson from "../package.json" with { type: "json" }
|
|
13
13
|
import { TracingLayer } from "./Tracing.ts"
|
|
14
14
|
import { MinimumLogLevel } from "effect/References"
|
|
15
15
|
import { atomRuntime, lalphMemoMap } from "./shared/runtime.ts"
|
|
16
16
|
import { PlatformServices } from "./shared/platform.ts"
|
|
17
|
-
import { commandProjects
|
|
17
|
+
import { commandProjects } from "./commands/projects.ts"
|
|
18
18
|
import { commandSh } from "./commands/sh.ts"
|
|
19
|
-
import { commandAgents
|
|
19
|
+
import { commandAgents } from "./commands/agents.ts"
|
|
20
20
|
|
|
21
21
|
commandRoot.pipe(
|
|
22
22
|
Command.withSubcommands([
|
|
@@ -27,10 +27,6 @@ commandRoot.pipe(
|
|
|
27
27
|
commandSource,
|
|
28
28
|
commandAgents,
|
|
29
29
|
commandProjects,
|
|
30
|
-
commandAgentsAlias,
|
|
31
|
-
commandEditAlias,
|
|
32
|
-
commandIssueAlias,
|
|
33
|
-
commandProjectsAlias,
|
|
34
30
|
]),
|
|
35
31
|
Command.provide(Settings.layer),
|
|
36
32
|
Command.provide(TracingLayer),
|
package/src/commands/agents.ts
CHANGED
|
@@ -15,12 +15,6 @@ export const commandAgents = Command.make("agents").pipe(
|
|
|
15
15
|
Command.withDescription(
|
|
16
16
|
"Manage agent presets used to run tasks. Use 'ls' to inspect presets and 'add'/'edit' to configure agents, arguments, and any issue-source options.",
|
|
17
17
|
),
|
|
18
|
-
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
export const commandAgentsAlias = Command.make("a").pipe(
|
|
22
|
-
Command.withDescription(
|
|
23
|
-
"Alias for 'agents' (manage agent presets used to run tasks).",
|
|
24
|
-
),
|
|
18
|
+
Command.withAlias("a"),
|
|
25
19
|
subcommands,
|
|
26
20
|
)
|
package/src/commands/edit.ts
CHANGED
|
@@ -22,12 +22,6 @@ export const commandEdit = Command.make("edit").pipe(
|
|
|
22
22
|
Command.withDescription(
|
|
23
23
|
"Open the selected project's .lalph/prd.yml in your editor.",
|
|
24
24
|
),
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
export const commandEditAlias = Command.make("e").pipe(
|
|
29
|
-
Command.withDescription(
|
|
30
|
-
"Alias for 'edit' (open the selected project's .lalph/prd.yml in your editor).",
|
|
31
|
-
),
|
|
25
|
+
Command.withAlias("e"),
|
|
32
26
|
handler,
|
|
33
27
|
)
|
package/src/commands/issue.ts
CHANGED
|
@@ -88,12 +88,6 @@ const handler = flow(
|
|
|
88
88
|
|
|
89
89
|
export const commandIssue = Command.make("issue").pipe(
|
|
90
90
|
Command.withDescription("Create a new issue in your editor."),
|
|
91
|
-
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
export const commandIssueAlias = Command.make("i").pipe(
|
|
95
|
-
Command.withDescription(
|
|
96
|
-
"Alias for 'issue' (create a new issue in your editor).",
|
|
97
|
-
),
|
|
91
|
+
Command.withAlias("i"),
|
|
98
92
|
handler,
|
|
99
93
|
)
|
|
@@ -7,7 +7,7 @@ import { PromptGen } from "../../PromptGen.ts"
|
|
|
7
7
|
import { Settings } from "../../Settings.ts"
|
|
8
8
|
import { Worktree } from "../../Worktree.ts"
|
|
9
9
|
import { commandRoot } from "../root.ts"
|
|
10
|
-
import {
|
|
10
|
+
import { selectCliAgentPreset } from "../../Presets.ts"
|
|
11
11
|
import { CurrentIssueSource } from "../../CurrentIssueSource.ts"
|
|
12
12
|
|
|
13
13
|
const specificationPath = Argument.path("spec", {
|
|
@@ -32,7 +32,7 @@ export const commandPlanTasks = Command.make("tasks", {
|
|
|
32
32
|
const fs = yield* FileSystem.FileSystem
|
|
33
33
|
const pathService = yield* Path.Path
|
|
34
34
|
const worktree = yield* Worktree
|
|
35
|
-
const preset = yield*
|
|
35
|
+
const preset = yield* selectCliAgentPreset
|
|
36
36
|
|
|
37
37
|
const content = yield* fs.readFileString(specificationPath)
|
|
38
38
|
const relative = pathService.relative(
|
package/src/commands/plan.ts
CHANGED
|
@@ -11,8 +11,8 @@ import { agentPlanner } from "../Agents/planner.ts"
|
|
|
11
11
|
import { agentTasker } from "../Agents/tasker.ts"
|
|
12
12
|
import { commandPlanTasks } from "./plan/tasks.ts"
|
|
13
13
|
import { Editor } from "../Editor.ts"
|
|
14
|
-
import {
|
|
15
|
-
import { ChildProcess } from "effect/unstable/process"
|
|
14
|
+
import { selectCliAgentPreset } from "../Presets.ts"
|
|
15
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
|
16
16
|
import { parseBranch } from "../shared/git.ts"
|
|
17
17
|
|
|
18
18
|
const dangerous = Flag.boolean("dangerous").pipe(
|
|
@@ -87,7 +87,7 @@ const plan = Effect.fnUntraced(
|
|
|
87
87
|
const fs = yield* FileSystem.FileSystem
|
|
88
88
|
const pathService = yield* Path.Path
|
|
89
89
|
const worktree = yield* Worktree
|
|
90
|
-
const preset = yield*
|
|
90
|
+
const preset = yield* selectCliAgentPreset
|
|
91
91
|
|
|
92
92
|
yield* agentPlanner({
|
|
93
93
|
plan: options.plan,
|
|
@@ -155,6 +155,7 @@ const commitAndPushSpecification = Effect.fnUntraced(
|
|
|
155
155
|
}) {
|
|
156
156
|
const worktree = yield* Worktree
|
|
157
157
|
const pathService = yield* Path.Path
|
|
158
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
158
159
|
|
|
159
160
|
const absSpecsDirectory = pathService.join(
|
|
160
161
|
worktree.directory,
|
|
@@ -166,7 +167,7 @@ const commitAndPushSpecification = Effect.fnUntraced(
|
|
|
166
167
|
cwd: worktree.directory,
|
|
167
168
|
stdout: "inherit",
|
|
168
169
|
stderr: "inherit",
|
|
169
|
-
}).pipe(
|
|
170
|
+
}).pipe(spawner.exitCode)
|
|
170
171
|
|
|
171
172
|
const addCode = yield* git(["add", absSpecsDirectory])
|
|
172
173
|
if (addCode !== 0) {
|
package/src/commands/projects.ts
CHANGED
|
@@ -17,10 +17,6 @@ export const commandProjects = Command.make("projects").pipe(
|
|
|
17
17
|
Command.withDescription(
|
|
18
18
|
"Manage projects and their execution settings (enabled state, concurrency, target branch, git flow, review agent). Use 'ls' to inspect and 'add', 'edit', or 'toggle' to configure.",
|
|
19
19
|
),
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
export const commandProjectsAlias = Command.make("p").pipe(
|
|
24
|
-
Command.withDescription("Alias for 'projects'."),
|
|
20
|
+
Command.withAlias("p"),
|
|
25
21
|
subcommands,
|
|
26
22
|
)
|
package/src/commands/sh.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from "effect/unstable/cli"
|
|
2
2
|
import { Effect, FileSystem, Layer, Path } from "effect"
|
|
3
|
-
import { ChildProcess } from "effect/unstable/process"
|
|
3
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
|
4
4
|
import { Prd } from "../Prd.ts"
|
|
5
5
|
import { Worktree } from "../Worktree.ts"
|
|
6
6
|
import { layerProjectIdPrompt } from "../Projects.ts"
|
|
@@ -17,6 +17,7 @@ export const commandSh = Command.make("sh").pipe(
|
|
|
17
17
|
const fs = yield* FileSystem.FileSystem
|
|
18
18
|
const pathService = yield* Path.Path
|
|
19
19
|
const lalphDirectory = yield* resolveLalphDirectory
|
|
20
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner
|
|
20
21
|
|
|
21
22
|
// link to lalph config
|
|
22
23
|
yield* fs.symlink(
|
|
@@ -33,7 +34,7 @@ export const commandSh = Command.make("sh").pipe(
|
|
|
33
34
|
stdin: "inherit",
|
|
34
35
|
stdout: "inherit",
|
|
35
36
|
stderr: "inherit",
|
|
36
|
-
}).pipe(
|
|
37
|
+
}).pipe(spawner.exitCode)
|
|
37
38
|
},
|
|
38
39
|
Effect.scoped,
|
|
39
40
|
Effect.provide(
|
package/src/shared/config.ts
CHANGED
package/src/shared/stream.ts
CHANGED
|
@@ -5,6 +5,6 @@ export const streamFilterJson = <S extends Schema.Top>(schema: S) => {
|
|
|
5
5
|
const decode = Schema.decodeEffect(fromString)
|
|
6
6
|
return flow(
|
|
7
7
|
Stream.splitLines,
|
|
8
|
-
Stream.
|
|
8
|
+
Stream.filterMapEffect((line) => decode(line).pipe(Effect.result)),
|
|
9
9
|
)
|
|
10
10
|
}
|