Skip to content

Commit 9b8e718

Browse files
committed
fix: register investigate command, gofumpt formatting, labs entry
- Register investigate command in root.go - Add investigate to labs experimental commands - Apply gofumpt formatting to 16 files - Update labs error message to mention investigate
1 parent c96cf02 commit 9b8e718

18 files changed

Lines changed: 110 additions & 52 deletions

cmd/trace/cli/agent/codex/spawner.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ func NewSpawner() spawn.Spawner { return codexSpawner{} }
2929
func (codexSpawner) Name() string { return string(agent.AgentNameCodex) }
3030

3131
func (codexSpawner) BuildCmd(ctx context.Context, env []string, prompt string) *exec.Cmd {
32-
cmd := exec.CommandContext(ctx, string(agent.AgentNameCodex),
32+
cmd := exec.CommandContext(
33+
ctx, string(agent.AgentNameCodex),
3334
codexExecCommand,
3435
"--skip-git-repo-check",
3536
"--dangerously-bypass-approvals-and-sandbox",

cmd/trace/cli/head_checkpoint_flags.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import (
77
"os/exec"
88

99
"github.com/GrayCodeAI/trace/cmd/trace/cli/checkpoint"
10+
"github.com/GrayCodeAI/trace/cmd/trace/cli/checkpoint/remote"
1011
"github.com/GrayCodeAI/trace/cmd/trace/cli/logging"
1112
"github.com/GrayCodeAI/trace/cmd/trace/cli/paths"
1213
"github.com/GrayCodeAI/trace/cmd/trace/cli/settings"
1314
"github.com/GrayCodeAI/trace/cmd/trace/cli/trailers"
14-
"github.com/GrayCodeAI/trace/cmd/trace/cli/checkpoint/remote"
1515
"github.com/go-git/go-git/v6"
1616
)
1717

cmd/trace/cli/integration_test/investigate_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,8 @@ func TestInvestigate_IssueLink_ResolvesViaFakeGh(t *testing.T) {
452452
"--max-turns", "1",
453453
"--agents", "claude-code")
454454
cmd.Dir = env.RepoDir
455-
cmd.Env = envWithOverrides(env.cliEnv(),
455+
cmd.Env = envWithOverrides(
456+
env.cliEnv(),
456457
"PATH="+fakeBinDir+string(os.PathListSeparator)+os.Getenv("PATH"),
457458
"ENTIRE_TEST_BINARY="+getTestBinary(),
458459
)

cmd/trace/cli/investigate/clean_test.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ func TestRunClean_RequiresArgOrAll(t *testing.T) {
9191

9292
env := newCleanTestEnv(t)
9393
var out, errOut bytes.Buffer
94-
err := RunClean(context.Background(),
94+
err := RunClean(
95+
context.Background(),
9596
CleanInput{Out: &out, ErrOut: &errOut},
9697
env.deps(nil),
9798
)
@@ -108,7 +109,8 @@ func TestRunClean_NoManifestsReportsEmpty(t *testing.T) {
108109

109110
env := newCleanTestEnv(t)
110111
var out, errOut bytes.Buffer
111-
err := RunClean(context.Background(),
112+
err := RunClean(
113+
context.Background(),
112114
CleanInput{All: true, Out: &out, ErrOut: &errOut},
113115
env.deps(nil),
114116
)
@@ -130,7 +132,8 @@ func TestRunClean_SingleByRunIDDeletes(t *testing.T) {
130132
env.seed(t, "bbbbbbbbbbbb", "second", t2)
131133

132134
var out, errOut bytes.Buffer
133-
err := RunClean(context.Background(),
135+
err := RunClean(
136+
context.Background(),
134137
CleanInput{RunID: "aaaaaaaaaaaa", Force: true, Out: &out, ErrOut: &errOut},
135138
env.deps(nil),
136139
)
@@ -167,7 +170,8 @@ func TestRunClean_PrefixMatchUnique(t *testing.T) {
167170
env.seed(t, "bbbbbbbbbbbb", "second", t2)
168171

169172
var out, errOut bytes.Buffer
170-
err := RunClean(context.Background(),
173+
err := RunClean(
174+
context.Background(),
171175
CleanInput{RunID: "aaaa", Force: true, Out: &out, ErrOut: &errOut},
172176
env.deps(nil),
173177
)
@@ -192,7 +196,8 @@ func TestRunClean_PrefixMatchAmbiguous(t *testing.T) {
192196
env.seed(t, "abc222222222", "second", t2)
193197

194198
var out, errOut bytes.Buffer
195-
err := RunClean(context.Background(),
199+
err := RunClean(
200+
context.Background(),
196201
CleanInput{RunID: "abc", Force: true, Out: &out, ErrOut: &errOut},
197202
env.deps(nil),
198203
)
@@ -221,7 +226,8 @@ func TestRunClean_AllDeletesEverything(t *testing.T) {
221226
env.seed(t, "bbbbbbbbbbbb", "second", t2)
222227

223228
var out, errOut bytes.Buffer
224-
err := RunClean(context.Background(),
229+
err := RunClean(
230+
context.Background(),
225231
CleanInput{All: true, Force: true, Out: &out, ErrOut: &errOut},
226232
env.deps(nil),
227233
)
@@ -249,7 +255,8 @@ func TestRunClean_ConfirmDeclinedAborts(t *testing.T) {
249255
confirm := func(_ context.Context, _ string) (bool, error) { return false, nil }
250256

251257
var out, errOut bytes.Buffer
252-
err := RunClean(context.Background(),
258+
err := RunClean(
259+
context.Background(),
253260
CleanInput{All: true, Out: &out, ErrOut: &errOut},
254261
env.deps(confirm),
255262
)
@@ -276,7 +283,8 @@ func TestRunClean_ForceSkipsConfirm(t *testing.T) {
276283
}
277284

278285
var out, errOut bytes.Buffer
279-
err := RunClean(context.Background(),
286+
err := RunClean(
287+
context.Background(),
280288
CleanInput{All: true, Force: true, Out: &out, ErrOut: &errOut},
281289
env.deps(confirm),
282290
)
@@ -300,7 +308,8 @@ func TestRunClean_MissingRunDirOK(t *testing.T) {
300308
}
301309

302310
var out, errOut bytes.Buffer
303-
err := RunClean(context.Background(),
311+
err := RunClean(
312+
context.Background(),
304313
CleanInput{RunID: "aaaaaaaaaaaa", Force: true, Out: &out, ErrOut: &errOut},
305314
env.deps(nil),
306315
)
@@ -347,7 +356,8 @@ func TestRunClean_AggregatesFailures(t *testing.T) {
347356
}
348357

349358
var out, errOut bytes.Buffer
350-
err := RunClean(context.Background(),
359+
err := RunClean(
360+
context.Background(),
351361
CleanInput{All: true, Force: true, Out: &out, ErrOut: &errOut},
352362
deps,
353363
)

cmd/trace/cli/investigate/cmd.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,8 @@ func runContinue(ctx context.Context, cmd *cobra.Command, f runFlags, deps Deps)
535535
"This usually means --agents was used with a shorter list than the original run. "+
536536
"Either re-run with the original agents (or a superset), or remove the run state at "+
537537
".git/trace-investigations/%s/state.json and start a fresh investigation",
538-
state.NextAgentIdx, len(agents), state.RunID)
538+
state.NextAgentIdx, len(agents), state.RunID,
539+
)
539540
cmd.SilenceUsage = true
540541
fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
541542
return wrapSilent(silentErr, err)

cmd/trace/cli/investigate/cmd_internal_test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,13 @@ func TestResolveDocPaths_PerRunIsolation(t *testing.T) {
5959
findings1 := resolveDocPaths(commonDir, "aaaaaaaaaaaa")
6060
findings2 := resolveDocPaths(commonDir, "bbbbbbbbbbbb")
6161

62-
require.Equal(t,
62+
require.Equal(
63+
t,
6364
filepath.Join(commonDir, "trace-investigations", "aaaaaaaaaaaa", "findings.md"),
6465
findings1,
6566
)
66-
require.Equal(t,
67+
require.Equal(
68+
t,
6769
filepath.Join(commonDir, "trace-investigations", "bbbbbbbbbbbb", "findings.md"),
6870
findings2,
6971
)

cmd/trace/cli/investigate/cmd_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,8 @@ func TestRunFresh_SkipsMultipickerWhenAgentsFlagPresent(t *testing.T) {
789789
require.NoError(t, os.MkdirAll(filepath.Join(tmp, ".trace"), 0o755))
790790
require.NoError(t, os.WriteFile(
791791
filepath.Join(tmp, ".trace/settings.local.json"),
792-
[]byte(`{"investigate":{"agents":["claude-code","codex"]}}`), 0o644))
792+
[]byte(`{"investigate":{"agents":["claude-code","codex"]}}`), 0o644,
793+
))
793794

794795
var pickerCalls int
795796
deps := investigate.Deps{
@@ -824,7 +825,8 @@ func TestRunFresh_InvokesMultipickerWhenTwoAgentsAndNoFlag(t *testing.T) {
824825
require.NoError(t, os.MkdirAll(filepath.Join(tmp, ".trace"), 0o755))
825826
require.NoError(t, os.WriteFile(
826827
filepath.Join(tmp, ".trace/settings.local.json"),
827-
[]byte(`{"investigate":{"agents":["claude-code","codex"]}}`), 0o644))
828+
[]byte(`{"investigate":{"agents":["claude-code","codex"]}}`), 0o644,
829+
))
828830

829831
var pickerCalled bool
830832
var pickerAskPrompt bool
@@ -868,7 +870,8 @@ func TestRunInvestigate_SoftWarnAcceptedRunsLoop(t *testing.T) {
868870
require.NoError(t, os.MkdirAll(filepath.Join(tmp, ".trace"), 0o755))
869871
require.NoError(t, os.WriteFile(
870872
filepath.Join(tmp, ".trace/settings.local.json"),
871-
[]byte(`{"investigate":{"agents":["claude-code"],"max_turns":1}}`), 0o644))
873+
[]byte(`{"investigate":{"agents":["claude-code"],"max_turns":1}}`), 0o644,
874+
))
872875

873876
var loopCalled bool
874877
deps := investigate.Deps{
@@ -910,7 +913,8 @@ func TestRunInvestigate_SoftWarnSilentInNonInteractive(t *testing.T) {
910913
require.NoError(t, os.MkdirAll(filepath.Join(tmp, ".trace"), 0o755))
911914
require.NoError(t, os.WriteFile(
912915
filepath.Join(tmp, ".trace/settings.local.json"),
913-
[]byte(`{"investigate":{"agents":["claude-code"],"max_turns":1}}`), 0o644))
916+
[]byte(`{"investigate":{"agents":["claude-code"],"max_turns":1}}`), 0o644,
917+
))
914918

915919
var loopCalled bool
916920
deps := investigate.Deps{

cmd/trace/cli/investigate/env.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ func AppendInvestigateEnv(base []string, opts AppendOptions) []string {
5757
}
5858
out = append(out, kv)
5959
}
60-
return append(out,
60+
return append(
61+
out,
6162
EnvSession+"=1",
6263
EnvAgent+"="+opts.AgentName,
6364
EnvRunID+"="+opts.RunID,

cmd/trace/cli/investigate/fix_test.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ func TestRunFix_PicksMostRecent(t *testing.T) {
6262
writeFixManifest(t, store, "bbbbbbbbbbbb", "newest topic", t2, "")
6363

6464
var rec fixLaunchRecord
65-
err := RunFix(context.Background(),
65+
err := RunFix(
66+
context.Background(),
6667
FixInput{Out: &bytes.Buffer{}},
6768
FixDeps{
6869
ManifestStore: store,
@@ -96,7 +97,8 @@ func TestRunFix_ResolvesByRunID(t *testing.T) {
9697
writeFixManifest(t, store, "bbbbbbbbbbbb", "newest topic", t2, "")
9798

9899
var rec fixLaunchRecord
99-
err := RunFix(context.Background(),
100+
err := RunFix(
101+
context.Background(),
100102
FixInput{RunID: "aaaaaaaaaaaa", Out: &bytes.Buffer{}},
101103
FixDeps{
102104
ManifestStore: store,
@@ -121,7 +123,8 @@ func TestRunFix_RunIDNotFound(t *testing.T) {
121123
writeFixManifest(t, store, "aaaaaaaaaaaa", "topic", time.Date(2026, 5, 1, 10, 0, 0, 0, time.UTC), "")
122124

123125
var rec fixLaunchRecord
124-
err := RunFix(context.Background(),
126+
err := RunFix(
127+
context.Background(),
125128
FixInput{RunID: "ffffffffffff"},
126129
FixDeps{
127130
ManifestStore: store,
@@ -145,7 +148,8 @@ func TestRunFix_NoManifests(t *testing.T) {
145148
store := NewLocalManifestStoreWithDir(t.TempDir())
146149

147150
var rec fixLaunchRecord
148-
err := RunFix(context.Background(),
151+
err := RunFix(
152+
context.Background(),
149153
FixInput{},
150154
FixDeps{
151155
ManifestStore: store,
@@ -172,7 +176,8 @@ func TestRunFix_ComposesPromptBody(t *testing.T) {
172176
now := time.Date(2026, 5, 8, 12, 0, 0, 0, time.UTC)
173177
// Absolute sentinel — readDocOrWarn rejects relative paths.
174178
findingsPath := filepath.Join(dir, "findings-sentinel.md")
175-
writeFixManifest(t, store, "abcdef012345", "Why is checkout flaky?", now,
179+
writeFixManifest(
180+
t, store, "abcdef012345", "Why is checkout flaky?", now,
176181
findingsPath,
177182
)
178183

@@ -185,7 +190,8 @@ func TestRunFix_ComposesPromptBody(t *testing.T) {
185190
}
186191

187192
var rec fixLaunchRecord
188-
err := RunFix(context.Background(),
193+
err := RunFix(
194+
context.Background(),
189195
FixInput{Out: &bytes.Buffer{}},
190196
FixDeps{
191197
ManifestStore: store,
@@ -224,13 +230,15 @@ func TestRunFix_TolerateMissingDocs(t *testing.T) {
224230
store := NewLocalManifestStoreWithDir(dir)
225231
now := time.Date(2026, 5, 8, 12, 0, 0, 0, time.UTC)
226232
// Manifest references a findings file that does not exist in dir.
227-
writeFixManifest(t, store, "abcdef012345", "topic", now,
233+
writeFixManifest(
234+
t, store, "abcdef012345", "topic", now,
228235
filepath.Join(dir, "missing-findings.md"),
229236
)
230237

231238
var rec fixLaunchRecord
232239
var errBuf bytes.Buffer
233-
err := RunFix(context.Background(),
240+
err := RunFix(
241+
context.Background(),
234242
FixInput{Out: &bytes.Buffer{}, ErrOut: &errBuf},
235243
FixDeps{
236244
ManifestStore: store,
@@ -280,7 +288,8 @@ func TestRunFix_PrefersFindingsContentOverDoc(t *testing.T) {
280288

281289
var rec fixLaunchRecord
282290
var errBuf bytes.Buffer
283-
err := RunFix(context.Background(),
291+
err := RunFix(
292+
context.Background(),
284293
FixInput{Out: &bytes.Buffer{}, ErrOut: &errBuf},
285294
FixDeps{ManifestStore: store, Launch: stubLaunch(&rec)},
286295
)
@@ -303,7 +312,8 @@ func TestRunFix_FallsBackToDefaultFixAgent(t *testing.T) {
303312
writeFixManifest(t, store, "abcdef012345", "topic", now, "")
304313

305314
var rec fixLaunchRecord
306-
err := RunFix(context.Background(),
315+
err := RunFix(
316+
context.Background(),
307317
FixInput{Out: &bytes.Buffer{}},
308318
FixDeps{
309319
ManifestStore: store,

cmd/trace/cli/investigate/loop_test.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ func TestRunInvestigateLoop_QuorumReachedFirstRound(t *testing.T) {
174174
StartingSHA: "deadbeef",
175175
}
176176
deps := LoopDeps{
177-
SpawnerFor: stableSpawner(t,
177+
SpawnerFor: stableSpawner(
178+
t,
178179
map[string]string{
179180
"claude-code": noopScript,
180181
"codex": noopScript,
@@ -223,7 +224,8 @@ func TestRunInvestigateLoop_QuorumDefault(t *testing.T) {
223224
StartingSHA: "deadbeef",
224225
}
225226
deps := LoopDeps{
226-
SpawnerFor: stableSpawner(t,
227+
SpawnerFor: stableSpawner(
228+
t,
227229
map[string]string{"claude-code": noopScript, "codex": noopScript},
228230
map[string]string{"claude-code": "approve", "codex": "approve"},
229231
),
@@ -256,7 +258,8 @@ func TestRunInvestigateLoop_Stalled(t *testing.T) {
256258
StartingSHA: "deadbeef",
257259
}
258260
deps := LoopDeps{
259-
SpawnerFor: stableSpawner(t,
261+
SpawnerFor: stableSpawner(
262+
t,
260263
map[string]string{"claude-code": noopScript, "codex": noopScript},
261264
map[string]string{"claude-code": "request-changes", "codex": "request-changes"},
262265
),
@@ -292,7 +295,8 @@ func TestRunInvestigateLoop_PausedOnTwoFailures(t *testing.T) {
292295
StartingSHA: "deadbeef",
293296
}
294297
deps := LoopDeps{
295-
SpawnerFor: stableSpawner(t,
298+
SpawnerFor: stableSpawner(
299+
t,
296300
map[string]string{"claude-code": failScript, "codex": failScript},
297301
// No stances written — agents fail before they could.
298302
map[string]string{},
@@ -341,7 +345,8 @@ func TestRunInvestigateLoop_UnknownStanceWhenPendingTurnMissing(t *testing.T) {
341345
StartingSHA: "deadbeef",
342346
}
343347
deps := LoopDeps{
344-
SpawnerFor: stableSpawner(t,
348+
SpawnerFor: stableSpawner(
349+
t,
345350
map[string]string{"claude-code": noopScript},
346351
// No stance — agent exits 0 without writing PendingTurn.
347352
map[string]string{},
@@ -384,7 +389,8 @@ func TestRunInvestigateLoop_MissingPendingTurnPausesAfterTwo(t *testing.T) {
384389
StartingSHA: "deadbeef",
385390
}
386391
deps := LoopDeps{
387-
SpawnerFor: stableSpawner(t,
392+
SpawnerFor: stableSpawner(
393+
t,
388394
map[string]string{"claude-code": noopScript, "codex": noopScript},
389395
map[string]string{}, // No stances
390396
),
@@ -679,7 +685,8 @@ func TestRunInvestigateLoop_InvalidStanceRecordedAsUnknown(t *testing.T) {
679685
StartingSHA: "deadbeef",
680686
}
681687
deps := LoopDeps{
682-
SpawnerFor: stableSpawner(t,
688+
SpawnerFor: stableSpawner(
689+
t,
683690
map[string]string{"claude-code": noopScript},
684691
map[string]string{"claude-code": "wibble"}, // not a valid stance
685692
),

0 commit comments

Comments
 (0)