summaryrefslogtreecommitdiff
path: root/internal/askcli/taskexec.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-13 08:09:33 +0300
committerPaul Buetow <paul@buetow.org>2026-04-13 08:10:16 +0300
commitf2dd8d8a515c1a2a220836231ad1a671a5e9b73d (patch)
tree5b19585afb01b60d03d24a96b57bc7b986ea4cc0 /internal/askcli/taskexec.go
parent56002ff942de1bfb0ce467ec37a692b8c4ca01e9 (diff)
ask: serialize concurrent CLI with repo lock and stale PID recovery
Add advisory lock under .git/hexai-ask.lock around Taskwarrior execution, with metadata (PID and process basename) and Linux /proc comm checks to remove orphan lock files when the recorded holder is gone or not ask. Extract internal/filelock for shared flock helpers; stats uses it too. Made-with: Cursor
Diffstat (limited to 'internal/askcli/taskexec.go')
-rw-r--r--internal/askcli/taskexec.go14
1 files changed, 11 insertions, 3 deletions
diff --git a/internal/askcli/taskexec.go b/internal/askcli/taskexec.go
index 0b68e3b..4eed461 100644
--- a/internal/askcli/taskexec.go
+++ b/internal/askcli/taskexec.go
@@ -77,17 +77,25 @@ func (e Executor) Run(ctx context.Context, args []string, stdin io.Reader, stdou
if err != nil {
return 1, fmt.Errorf("%s: task binary lookup failed: %w", executor.label(), err)
}
+ gitRoot, gitErr := executor.detectRepoRoot(ctx)
repoRoot := ""
if _, ok := taskProjectFromContext(ctx); !ok {
- repoRoot, err = executor.detectRepoRoot(ctx)
- if err != nil {
- return 1, fmt.Errorf("%s: must be run inside a git repository: %w", executor.label(), err)
+ if gitErr != nil {
+ return 1, fmt.Errorf("%s: must be run inside a git repository: %w", executor.label(), gitErr)
}
+ repoRoot = gitRoot
}
taskArgs, err := executor.taskArgs(ctx, repoRoot, args)
if err != nil {
return 1, fmt.Errorf("%s: %w", executor.label(), err)
}
+ if gitErr == nil {
+ unlockAsk, lerr := acquireAskRepoLock(ctx, gitRoot)
+ if lerr != nil {
+ return 1, fmt.Errorf("%s: %w", executor.label(), lerr)
+ }
+ defer func() { _ = unlockAsk() }()
+ }
if err := executor.runCommand(ctx, taskPath, taskArgs, stdin, stdout, stderr); err != nil {
return exitCodeFor(err), nil
}