@markjaquith/agency 0.7.3 → 0.8.0
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/package.json +1 -1
- package/src/commands/task-edit.test.ts +94 -0
- package/src/commands/task.ts +21 -0
- package/src/services/GitService.ts +16 -0
package/package.json
CHANGED
|
@@ -8,7 +8,10 @@ import {
|
|
|
8
8
|
initAgency,
|
|
9
9
|
readFile,
|
|
10
10
|
runTestEffect,
|
|
11
|
+
createFile,
|
|
12
|
+
runGitCommand,
|
|
11
13
|
} from "../test-utils"
|
|
14
|
+
import { chmod } from "fs/promises"
|
|
12
15
|
|
|
13
16
|
describe("edit command", () => {
|
|
14
17
|
let tempDir: string
|
|
@@ -138,4 +141,95 @@ describe("edit command", () => {
|
|
|
138
141
|
"Editor exited with code",
|
|
139
142
|
)
|
|
140
143
|
})
|
|
144
|
+
|
|
145
|
+
test("commits TASK.md with 'chore: agency edit' when file is modified", async () => {
|
|
146
|
+
await initGitRepo(tempDir)
|
|
147
|
+
process.chdir(tempDir)
|
|
148
|
+
|
|
149
|
+
// Initialize to create TASK.md
|
|
150
|
+
await initAgency(tempDir, "test-task")
|
|
151
|
+
await runTestEffect(task({ silent: true, emit: "test-feature" }))
|
|
152
|
+
|
|
153
|
+
// Get initial commit count
|
|
154
|
+
const result = Bun.spawnSync({
|
|
155
|
+
cmd: ["git", "rev-list", "--count", "HEAD"],
|
|
156
|
+
cwd: tempDir,
|
|
157
|
+
stdout: "pipe",
|
|
158
|
+
})
|
|
159
|
+
const initialCommits = new TextDecoder().decode(result.stdout).trim()
|
|
160
|
+
|
|
161
|
+
// Use a script that modifies TASK.md
|
|
162
|
+
const scriptPath = join(tempDir, "edit-script.sh")
|
|
163
|
+
await createFile(
|
|
164
|
+
tempDir,
|
|
165
|
+
"edit-script.sh",
|
|
166
|
+
'#!/bin/bash\necho "Updated task" >> "$1"\n',
|
|
167
|
+
)
|
|
168
|
+
await chmod(scriptPath, 0o755)
|
|
169
|
+
process.env.EDITOR = scriptPath
|
|
170
|
+
|
|
171
|
+
// Run edit command
|
|
172
|
+
await runTestEffect(taskEdit({ silent: true }))
|
|
173
|
+
|
|
174
|
+
// Check that a new commit was created
|
|
175
|
+
const finalResult = Bun.spawnSync({
|
|
176
|
+
cmd: ["git", "rev-list", "--count", "HEAD"],
|
|
177
|
+
cwd: tempDir,
|
|
178
|
+
stdout: "pipe",
|
|
179
|
+
})
|
|
180
|
+
const finalCommits = new TextDecoder().decode(finalResult.stdout).trim()
|
|
181
|
+
expect(Number.parseInt(finalCommits)).toBe(
|
|
182
|
+
Number.parseInt(initialCommits) + 1,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
// Check the commit message
|
|
186
|
+
const msgResult = Bun.spawnSync({
|
|
187
|
+
cmd: ["git", "log", "-1", "--format=%s"],
|
|
188
|
+
cwd: tempDir,
|
|
189
|
+
stdout: "pipe",
|
|
190
|
+
})
|
|
191
|
+
const commitMessage = new TextDecoder().decode(msgResult.stdout).trim()
|
|
192
|
+
expect(commitMessage).toBe("chore: agency edit")
|
|
193
|
+
|
|
194
|
+
// Check that only TASK.md was committed
|
|
195
|
+
const filesResult = Bun.spawnSync({
|
|
196
|
+
cmd: ["git", "diff-tree", "--no-commit-id", "--name-only", "-r", "HEAD"],
|
|
197
|
+
cwd: tempDir,
|
|
198
|
+
stdout: "pipe",
|
|
199
|
+
})
|
|
200
|
+
const filesInCommit = new TextDecoder().decode(filesResult.stdout).trim()
|
|
201
|
+
expect(filesInCommit).toBe("TASK.md")
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
test("does not commit when TASK.md is not modified", async () => {
|
|
205
|
+
await initGitRepo(tempDir)
|
|
206
|
+
process.chdir(tempDir)
|
|
207
|
+
|
|
208
|
+
// Initialize to create TASK.md
|
|
209
|
+
await initAgency(tempDir, "test-task")
|
|
210
|
+
await runTestEffect(task({ silent: true, emit: "test-feature" }))
|
|
211
|
+
|
|
212
|
+
// Get initial commit count
|
|
213
|
+
const result = Bun.spawnSync({
|
|
214
|
+
cmd: ["git", "rev-list", "--count", "HEAD"],
|
|
215
|
+
cwd: tempDir,
|
|
216
|
+
stdout: "pipe",
|
|
217
|
+
})
|
|
218
|
+
const initialCommits = new TextDecoder().decode(result.stdout).trim()
|
|
219
|
+
|
|
220
|
+
// Use a mock editor that doesn't modify the file
|
|
221
|
+
process.env.EDITOR = "true"
|
|
222
|
+
|
|
223
|
+
// Run edit command
|
|
224
|
+
await runTestEffect(taskEdit({ silent: true }))
|
|
225
|
+
|
|
226
|
+
// Check that no new commit was created
|
|
227
|
+
const finalResult = Bun.spawnSync({
|
|
228
|
+
cmd: ["git", "rev-list", "--count", "HEAD"],
|
|
229
|
+
cwd: tempDir,
|
|
230
|
+
stdout: "pipe",
|
|
231
|
+
})
|
|
232
|
+
const finalCommits = new TextDecoder().decode(finalResult.stdout).trim()
|
|
233
|
+
expect(Number.parseInt(finalCommits)).toBe(Number.parseInt(initialCommits))
|
|
234
|
+
})
|
|
141
235
|
})
|
package/src/commands/task.ts
CHANGED
|
@@ -910,6 +910,7 @@ const taskEditEffect = (options: TaskEditOptions = {}) =>
|
|
|
910
910
|
const { log, verboseLog } = createLoggers(options)
|
|
911
911
|
|
|
912
912
|
const fs = yield* FileSystemService
|
|
913
|
+
const git = yield* GitService
|
|
913
914
|
|
|
914
915
|
const gitRoot = yield* ensureGitRepo()
|
|
915
916
|
|
|
@@ -943,6 +944,26 @@ const taskEditEffect = (options: TaskEditOptions = {}) =>
|
|
|
943
944
|
}
|
|
944
945
|
|
|
945
946
|
log(done("TASK.md edited"))
|
|
947
|
+
|
|
948
|
+
// Check if TASK.md has uncommitted changes
|
|
949
|
+
const hasChanges = yield* git.hasUncommittedChanges(gitRoot, "TASK.md")
|
|
950
|
+
verboseLog(`TASK.md has uncommitted changes: ${hasChanges}`)
|
|
951
|
+
|
|
952
|
+
if (hasChanges) {
|
|
953
|
+
// Commit the changes
|
|
954
|
+
yield* Effect.gen(function* () {
|
|
955
|
+
yield* git.gitAdd(["TASK.md"], gitRoot)
|
|
956
|
+
yield* git.gitCommit("chore: agency edit", gitRoot, {
|
|
957
|
+
noVerify: true,
|
|
958
|
+
})
|
|
959
|
+
log(done("Committed TASK.md changes"))
|
|
960
|
+
}).pipe(
|
|
961
|
+
Effect.catchAll((err) => {
|
|
962
|
+
verboseLog(`Failed to commit TASK.md: ${err}`)
|
|
963
|
+
return Effect.void
|
|
964
|
+
}),
|
|
965
|
+
)
|
|
966
|
+
}
|
|
946
967
|
})
|
|
947
968
|
|
|
948
969
|
export const editHelp = `
|
|
@@ -850,5 +850,21 @@ export class GitService extends Effect.Service<GitService>()("GitService", {
|
|
|
850
850
|
Effect.map((result) => (result.exitCode === 0 ? result.stdout : null)),
|
|
851
851
|
Effect.catchAll(() => Effect.succeed(null)),
|
|
852
852
|
),
|
|
853
|
+
|
|
854
|
+
/**
|
|
855
|
+
* Check if a file has uncommitted changes (staged or unstaged).
|
|
856
|
+
* Uses `git diff HEAD` to check for any changes to the file.
|
|
857
|
+
* @param gitRoot - The git repository root
|
|
858
|
+
* @param filePath - Path to the file relative to git root
|
|
859
|
+
* @returns true if the file has changes, false otherwise
|
|
860
|
+
*/
|
|
861
|
+
hasUncommittedChanges: (gitRoot: string, filePath: string) =>
|
|
862
|
+
pipe(
|
|
863
|
+
runGitCommand(["git", "diff", "HEAD", "--", filePath], gitRoot),
|
|
864
|
+
Effect.map(
|
|
865
|
+
(result) => result.exitCode === 0 && result.stdout.length > 0,
|
|
866
|
+
),
|
|
867
|
+
Effect.catchAll(() => Effect.succeed(false)),
|
|
868
|
+
),
|
|
853
869
|
}),
|
|
854
870
|
}) {}
|