From 13238aa91dc8dea31bdf5c82fe69ac8780c1574e Mon Sep 17 00:00:00 2001 From: Stefan Haubold Date: Wed, 25 Mar 2026 18:00:43 +0100 Subject: [PATCH 1/2] rewrite opencode plugin if content differs Entire-Checkpoint: f92b8ef4844d --- cmd/entire/cli/agent/opencode/hooks.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/cmd/entire/cli/agent/opencode/hooks.go b/cmd/entire/cli/agent/opencode/hooks.go index 35b8ed459..7e425e02f 100644 --- a/cmd/entire/cli/agent/opencode/hooks.go +++ b/cmd/entire/cli/agent/opencode/hooks.go @@ -47,16 +47,6 @@ func (a *OpenCodeAgent) InstallHooks(ctx context.Context, localDev bool, force b return 0, err } - // Check if already installed (idempotent) unless force - if !force { - if _, err := os.Stat(pluginPath); err == nil { - data, readErr := os.ReadFile(pluginPath) //nolint:gosec // Path constructed from repo root - if readErr == nil && strings.Contains(string(data), entireMarker) { - return 0, nil // Already installed - } - } - } - // Build the command prefix var cmdPrefix string if localDev { @@ -68,6 +58,15 @@ func (a *OpenCodeAgent) InstallHooks(ctx context.Context, localDev bool, force b // Generate plugin content from template content := strings.ReplaceAll(pluginTemplate, entireCmdPlaceholder, cmdPrefix) + // Check if already installed with identical content (idempotent) unless force + if !force { + if existing, readErr := os.ReadFile(pluginPath); readErr == nil { //nolint:gosec // Path constructed from repo root + if string(existing) == content { + return 0, nil // Already up-to-date + } + } + } + // Ensure directory exists pluginDir := filepath.Dir(pluginPath) //nolint:gosec // G301: Plugin directory needs standard permissions From d6c33535f22cf051277164857fc03687c5f2bcd0 Mon Sep 17 00:00:00 2001 From: Stefan Haubold Date: Fri, 27 Mar 2026 17:06:15 +0100 Subject: [PATCH 2/2] pr feedback Entire-Checkpoint: e6078379e8f7 --- cmd/entire/cli/agent/opencode/hooks.go | 3 +- cmd/entire/cli/agent/opencode/hooks_test.go | 44 +++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/cmd/entire/cli/agent/opencode/hooks.go b/cmd/entire/cli/agent/opencode/hooks.go index 7e425e02f..02b2f7cb7 100644 --- a/cmd/entire/cli/agent/opencode/hooks.go +++ b/cmd/entire/cli/agent/opencode/hooks.go @@ -40,7 +40,8 @@ func getPluginPath(ctx context.Context) (string, error) { } // InstallHooks writes the Entire plugin file to .opencode/plugins/entire.ts. -// Returns 1 if the plugin was installed, 0 if already present (idempotent). +// Returns 1 if the plugin was written, 0 if already up-to-date (idempotent). +// If the file exists but content differs (e.g., localDev vs production), it is rewritten. func (a *OpenCodeAgent) InstallHooks(ctx context.Context, localDev bool, force bool) (int, error) { pluginPath, err := getPluginPath(ctx) if err != nil { diff --git a/cmd/entire/cli/agent/opencode/hooks_test.go b/cmd/entire/cli/agent/opencode/hooks_test.go index 744714b26..a5c717cb5 100644 --- a/cmd/entire/cli/agent/opencode/hooks_test.go +++ b/cmd/entire/cli/agent/opencode/hooks_test.go @@ -121,6 +121,50 @@ func TestInstallHooks_ForceReinstall(t *testing.T) { } } +func TestInstallHooks_RewritesWhenContentDiffers(t *testing.T) { + dir := t.TempDir() + t.Chdir(dir) + ag := &OpenCodeAgent{} + + // Install with localDev=true + count, err := ag.InstallHooks(context.Background(), true, false) + if err != nil { + t.Fatalf("first install failed: %v", err) + } + if count != 1 { + t.Errorf("first install: expected 1, got %d", count) + } + + pluginPath := filepath.Join(dir, ".opencode", "plugins", "entire.ts") + before, err := os.ReadFile(pluginPath) + if err != nil { + t.Fatalf("failed to read plugin file: %v", err) + } + if !strings.Contains(string(before), "go run") { + t.Fatal("expected localDev content with 'go run'") + } + + // Reinstall with localDev=false (content differs) — should rewrite + count, err = ag.InstallHooks(context.Background(), false, false) + if err != nil { + t.Fatalf("second install failed: %v", err) + } + if count != 1 { + t.Errorf("second install with different content: expected 1, got %d", count) + } + + after, err := os.ReadFile(pluginPath) + if err != nil { + t.Fatalf("failed to read plugin file after rewrite: %v", err) + } + if strings.Contains(string(after), "go run") { + t.Error("expected production content after rewrite, but still contains 'go run'") + } + if !strings.Contains(string(after), `const ENTIRE_CMD = 'entire'`) { + t.Error("expected production command constant after rewrite") + } +} + func TestUninstallHooks(t *testing.T) { dir := t.TempDir() t.Chdir(dir)