Files
Duy /zuey/ d4463cde6f fix(exec): surface real cwd error + auto-normalize stale workspace paths (#77)
* fix(exec): surface chdir error instead of misleading fork/exec

Linux Go forkAndExecInChild conflates chdir + execve failures into one
PathError naming only argv0. When agent workspace points to a stale
directory, exec reports "fork/exec /usr/bin/gh: no such file" even though
the binary exists — the real failure is chdir on cmd.Dir.

Two fixes:
- loop_context.go: fall back to l.workspace when per-user MkdirAll fails
  (3 sites: user workspace, dispatched team, auto-resolved team)
- shell.go + credentialed_exec.go: preflight cwd via validateExecCwd
  before exec.Command, so the error names the directory, not the binary

Regression test TestValidateExecCwd covers empty / existing / missing /
file-instead-of-dir.

* feat(upgrade): auto-normalize stale agent workspace paths

Detects non-portable workspace values left by deployment migrations
(Docker → bare-metal, host path drift) and rewrites them to the current
configured base. Registered as data hook 072_normalize_agent_workspaces;
runs automatically after `migrate up`.

Stale patterns:
- /app/workspace/* (Docker container path persisted on bare-metal)
- ~ prefix (Go doesn't expand tildes; MkdirAll creates literal ~ dir)

Base resolved with gateway precedence: GOCLAW_WORKSPACE env >
config.Agents.Defaults.Workspace > default ~/.goclaw/workspace.
Idempotent (skips rows already at proposed value). Conservative
(leaves absolute non-stale paths untouched as intentional custom config).
2026-05-27 11:52:25 +07:00

26 lines
635 B
Go

package upgrade
import (
"context"
"database/sql"
)
// Data migration hooks are registered here.
// Add new hooks when a schema migration requires Go-based data transformation.
//
// Example:
//
// func init() {
// RegisterDataHook(8, "008_backfill_agent_slugs", func(ctx context.Context, db *sql.DB) error {
// // transform data after migration 000008 is applied
// return nil
// })
// }
func init() {
RegisterDataHook(55, webSearchMigrateHookName, func(ctx context.Context, db *sql.DB) error {
return migrateWebSearchInlineKeys(ctx, db)
})
RegisterDataHook(72, workspaceNormalizeHookName, normalizeAgentWorkspaces)
}