fix: critical issues in wisp hook system
Code review fixes: 1. CRITICAL: Move polecat check to start of runSling - Previously wrote wisp THEN failed, leaving orphan - Now fails fast before any file operations 2. CRITICAL: Sanitize slashes in agent IDs for filenames - Agent IDs like 'gastown/crew/joe' were creating subdirs - Now converts '/' to '--' for safe filenames - Added sanitizeAgentID/unsanitizeAgentID helpers 3. MODERATE: Use git root instead of WorkDir in prime.go - Hooks are written to clone root, not cwd - Added getGitRoot() helper for consistency 4. MODERATE: Fix silent error swallowing - Now logs non-ErrNoHook errors when reading hooks - Warns if bead doesn't exist before burning hook - Preserves hook if bead is missing for debugging
This commit is contained in:
@@ -1169,15 +1169,21 @@ func checkSlungWork(ctx RoleContext) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for hook file in the clone root
|
||||
cloneRoot := ctx.WorkDir
|
||||
// Get the git clone root (hooks are stored at clone root, not cwd)
|
||||
cloneRoot, err := getGitRoot()
|
||||
if err != nil {
|
||||
// Not in a git repo - can't have hooks
|
||||
return
|
||||
}
|
||||
|
||||
sw, err := wisp.ReadHook(cloneRoot, agentID)
|
||||
if err != nil {
|
||||
if errors.Is(err, wisp.ErrNoHook) {
|
||||
// No hook - normal case, nothing to do
|
||||
return
|
||||
}
|
||||
// Other error - log but continue
|
||||
// Log other errors (permission, corruption) but continue
|
||||
fmt.Printf("%s Warning: error reading hook: %v\n", style.Dim.Render("⚠"), err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1196,14 +1202,15 @@ func checkSlungWork(ctx RoleContext) {
|
||||
fmt.Printf(" Slung at: %s\n", sw.CreatedAt.Format("2006-01-02 15:04:05"))
|
||||
fmt.Println()
|
||||
|
||||
// Show the bead details
|
||||
// Show the bead details - verify it exists
|
||||
fmt.Println("**Bead details:**")
|
||||
cmd := exec.Command("bd", "show", sw.BeadID)
|
||||
cmd.Dir = cloneRoot
|
||||
var stdout bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = nil
|
||||
if cmd.Run() == nil {
|
||||
beadExists := cmd.Run() == nil
|
||||
if beadExists {
|
||||
// Show first 20 lines of bead details
|
||||
lines := strings.Split(stdout.String(), "\n")
|
||||
maxLines := 20
|
||||
@@ -1214,6 +1221,13 @@ func checkSlungWork(ctx RoleContext) {
|
||||
for _, line := range lines {
|
||||
fmt.Printf(" %s\n", line)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf(" %s Bead %s not found! It may have been deleted.\n",
|
||||
style.Bold.Render("⚠ WARNING:"), sw.BeadID)
|
||||
fmt.Println(" The hook will NOT be burned. Investigate this issue.")
|
||||
fmt.Println()
|
||||
// Don't burn - leave hook for debugging
|
||||
return
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
@@ -1222,12 +1236,22 @@ func checkSlungWork(ctx RoleContext) {
|
||||
fmt.Println(" Begin working on this bead immediately. No human input needed.")
|
||||
fmt.Println()
|
||||
|
||||
// Burn the hook now that it's been read
|
||||
// Burn the hook now that it's been read and verified
|
||||
if err := wisp.BurnHook(cloneRoot, agentID); err != nil {
|
||||
fmt.Printf("%s Warning: could not burn hook: %v\n", style.Dim.Render("⚠"), err)
|
||||
}
|
||||
}
|
||||
|
||||
// getGitRoot returns the root of the current git repository.
|
||||
func getGitRoot() (string, error) {
|
||||
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(out)), nil
|
||||
}
|
||||
|
||||
// getAgentIdentity returns the agent identity string for hook lookup.
|
||||
func getAgentIdentity(ctx RoleContext) string {
|
||||
switch ctx.Role {
|
||||
|
||||
@@ -50,6 +50,11 @@ func init() {
|
||||
func runSling(cmd *cobra.Command, args []string) error {
|
||||
beadID := args[0]
|
||||
|
||||
// Polecats cannot sling - check early before writing anything
|
||||
if polecatName := os.Getenv("GT_POLECAT"); polecatName != "" {
|
||||
return fmt.Errorf("polecats cannot sling (use gt done for handoff)")
|
||||
}
|
||||
|
||||
// Verify the bead exists
|
||||
if err := verifyBeadExists(beadID); err != nil {
|
||||
return err
|
||||
@@ -166,13 +171,6 @@ func detectCloneRoot() (string, error) {
|
||||
|
||||
// triggerHandoff restarts the agent session.
|
||||
func triggerHandoff(agentID, beadID string) error {
|
||||
// Check if we're a polecat
|
||||
if polecatName := os.Getenv("GT_POLECAT"); polecatName != "" {
|
||||
fmt.Printf("%s Polecat detected - cannot sling (use gt done instead)\n",
|
||||
style.Bold.Render("⚠"))
|
||||
return fmt.Errorf("polecats cannot sling - use gt done for handoff")
|
||||
}
|
||||
|
||||
// Must be in tmux
|
||||
if !tmux.IsInsideTmux() {
|
||||
return fmt.Errorf("not running in tmux - cannot restart")
|
||||
|
||||
Reference in New Issue
Block a user