@markjaquith/agency 0.7.2 → 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
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 = `
|
|
@@ -141,7 +141,7 @@ describe("work command", () => {
|
|
|
141
141
|
restore()
|
|
142
142
|
|
|
143
143
|
expect(spawnCalled).toBe(true)
|
|
144
|
-
expect(spawnArgs).toEqual(["opencode", "
|
|
144
|
+
expect(spawnArgs).toEqual(["opencode", "--prompt", "Start the task"])
|
|
145
145
|
})
|
|
146
146
|
})
|
|
147
147
|
|
|
@@ -171,7 +171,7 @@ describe("work command", () => {
|
|
|
171
171
|
|
|
172
172
|
restore()
|
|
173
173
|
|
|
174
|
-
expect(capturedArgs).toEqual(["opencode", "
|
|
174
|
+
expect(capturedArgs).toEqual(["opencode", "--prompt", "Start the task"])
|
|
175
175
|
// On macOS, temp directories can have /private prefix
|
|
176
176
|
expect(
|
|
177
177
|
capturedOptions.cwd === tempDir ||
|
|
@@ -278,7 +278,7 @@ describe("work command", () => {
|
|
|
278
278
|
|
|
279
279
|
restore()
|
|
280
280
|
|
|
281
|
-
expect(capturedArgs).toEqual(["opencode", "
|
|
281
|
+
expect(capturedArgs).toEqual(["opencode", "--prompt", "Start the task"])
|
|
282
282
|
})
|
|
283
283
|
|
|
284
284
|
test("--claude flag forces use of Claude Code", async () => {
|
|
@@ -387,7 +387,7 @@ describe("work command", () => {
|
|
|
387
387
|
|
|
388
388
|
expect(capturedArgs).toEqual([
|
|
389
389
|
"opencode",
|
|
390
|
-
"
|
|
390
|
+
"--prompt",
|
|
391
391
|
"Start the task",
|
|
392
392
|
"--model",
|
|
393
393
|
"claude-sonnet-4-20250514",
|
|
@@ -456,7 +456,7 @@ describe("work command", () => {
|
|
|
456
456
|
|
|
457
457
|
restore()
|
|
458
458
|
|
|
459
|
-
expect(capturedArgs).toEqual(["opencode", "
|
|
459
|
+
expect(capturedArgs).toEqual(["opencode", "--prompt", "Start the task"])
|
|
460
460
|
})
|
|
461
461
|
})
|
|
462
462
|
})
|
package/src/commands/work.ts
CHANGED
|
@@ -117,7 +117,7 @@ export const work = (options: WorkOptions = {}) =>
|
|
|
117
117
|
|
|
118
118
|
const cliName = useOpencode ? "opencode" : "claude"
|
|
119
119
|
const baseArgs = useOpencode
|
|
120
|
-
? [cliName, "
|
|
120
|
+
? [cliName, "--prompt", "Start the task"]
|
|
121
121
|
: [cliName, "Start the task"]
|
|
122
122
|
|
|
123
123
|
// Append extra args if provided
|
|
@@ -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
|
}) {}
|