From 60f4cb6fdb660cc932d4b1e8ece045c378e2e6e6 Mon Sep 17 00:00:00 2001 From: Snider Date: Sat, 18 Apr 2026 08:34:52 +0100 Subject: [PATCH] feat(agent): gpt-5.4-mini/mature pass 2 - `git add` / `git commit` fail with `Operation not permitted` on `.git/index.lock` - even a plain `touch .git/...` is blocked Co-Authored-By: Virgil --- .core/TODO.md | 2 -- pkg/agentic/deps.go | 17 ++++++++++++----- pkg/agentic/deps_test.go | 8 ++++++-- pkg/agentic/prep.go | 11 +++++++++-- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/.core/TODO.md b/.core/TODO.md index 66e7e31..e69de29 100644 --- a/.core/TODO.md +++ b/.core/TODO.md @@ -1,2 +0,0 @@ -- @bug pkg/agentic/deps.go:59 — `go.work` is written without checking the result, so dependency cloning can fail silently. -- @bug pkg/agentic/prep.go:835 — the PHP-specific `CODEX.md` overwrite ignores write failures, leaving prep to continue with a partial workspace. diff --git a/pkg/agentic/deps.go b/pkg/agentic/deps.go index 845f5f6..742c6fb 100644 --- a/pkg/agentic/deps.go +++ b/pkg/agentic/deps.go @@ -9,18 +9,18 @@ import ( ) // s.cloneWorkspaceDeps(ctx, workspaceDir, repoDir, "core") -func (s *PrepSubsystem) cloneWorkspaceDeps(ctx context.Context, workspaceDir, repoDir, org string) { +func (s *PrepSubsystem) cloneWorkspaceDeps(ctx context.Context, workspaceDir, repoDir, org string) error { goModPath := core.JoinPath(repoDir, "go.mod") r := fs.Read(goModPath) if !r.OK { - return + return nil } deps := parseCoreDeps(r.Value.(string)) if len(deps) == 0 { - return + return nil } if s.ServiceRuntime == nil { - return + return nil } process := s.Core().Process() @@ -56,8 +56,15 @@ func (s *PrepSubsystem) cloneWorkspaceDeps(ctx context.Context, workspaceDir, re b.WriteString(core.Concat("\t./", dir, "\n")) } b.WriteString(")\n") - fs.Write(core.JoinPath(workspaceDir, "go.work"), b.String()) + if r := fs.WriteAtomic(core.JoinPath(workspaceDir, "go.work"), b.String()); !r.OK { + if err, ok := r.Value.(error); ok { + return core.E("cloneWorkspaceDeps", "write go.work", err) + } + return core.E("cloneWorkspaceDeps", "write go.work", nil) + } } + + return nil } // dep := coreDep{module: "dappco.re/go/core", repo: "go", dir: "core-go"} diff --git a/pkg/agentic/deps_test.go b/pkg/agentic/deps_test.go index 76f83cd..a6dca75 100644 --- a/pkg/agentic/deps_test.go +++ b/pkg/agentic/deps_test.go @@ -70,7 +70,9 @@ func TestDeps_CloneWorkspaceDeps_Bad_NoGoMod(t *testing.T) { } subsystem := &PrepSubsystem{} - subsystem.cloneWorkspaceDeps(context.Background(), wsDir, repoDir, "core") + if err := subsystem.cloneWorkspaceDeps(context.Background(), wsDir, repoDir, "core"); err != nil { + t.Fatalf("clone workspace deps: %v", err) + } assert.False(t, fs.IsFile(core.JoinPath(wsDir, "go.work"))) } @@ -95,7 +97,9 @@ require ( } subsystem := &PrepSubsystem{} - subsystem.cloneWorkspaceDeps(context.Background(), wsDir, repoDir, "core") + if err := subsystem.cloneWorkspaceDeps(context.Background(), wsDir, repoDir, "core"); err != nil { + t.Fatalf("clone workspace deps: %v", err) + } assert.False(t, fs.IsFile(core.JoinPath(wsDir, "go.work"))) } diff --git a/pkg/agentic/prep.go b/pkg/agentic/prep.go index d5d2209..01ffe65 100644 --- a/pkg/agentic/prep.go +++ b/pkg/agentic/prep.go @@ -832,11 +832,18 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques if lang == "php" { if r := lib.WorkspaceFile("default", "CODEX-PHP.md.tmpl"); r.OK { codexPath := core.JoinPath(workspaceDir, "CODEX.md") - fs.Write(codexPath, r.Value.(string)) + if writeResult := fs.WriteAtomic(codexPath, r.Value.(string)); !writeResult.OK { + if err, ok := writeResult.Value.(error); ok { + return nil, PrepOutput{}, core.E("prepWorkspace", "write CODEX.md", err) + } + return nil, PrepOutput{}, core.E("prepWorkspace", "write CODEX.md", nil) + } } } - s.cloneWorkspaceDeps(ctx, workspaceDir, repoDir, input.Org) + if err := s.cloneWorkspaceDeps(ctx, workspaceDir, repoDir, input.Org); err != nil { + return nil, PrepOutput{}, err + } if err := s.runWorkspaceLanguagePrep(ctx, workspaceDir, repoDir); err != nil { return nil, PrepOutput{}, err }