← back to jpmarques19__treehouse

Function bodies 56 total

All specs Real LLM only Function bodies
agent.DeleteMemoryFiles function · go · L12-L40 (29 LOC)
internal/agent/memory.go
func DeleteMemoryFiles(treehousePath, nookID string) error {
	// Validate nookID to prevent path traversal
	if err := nook.ValidateNookID(nookID); err != nil {
		return err
	}

	agentsPath := filepath.Join(treehousePath, "agents")

	// Check if agents directory exists
	if _, err := os.Stat(agentsPath); os.IsNotExist(err) {
		return nil // Nothing to clean up
	}

	// Pattern: .treehouse/agents/*/memories/{nook-id}.md
	memPattern := filepath.Join(agentsPath, "*", "memories", nookID+".md")
	memFiles, _ := filepath.Glob(memPattern)
	for _, f := range memFiles {
		_ = os.Remove(f) // Best-effort removal
	}

	// Pattern: .treehouse/agents/*/sessions/{nook-id}.md
	sessPattern := filepath.Join(agentsPath, "*", "sessions", nookID+".md")
	sessFiles, _ := filepath.Glob(sessPattern)
	for _, f := range sessFiles {
		_ = os.Remove(f) // Best-effort removal
	}

	return nil
}
board.LoadBoards function · go · L36-L67 (32 LOC)
internal/board/board.go
func LoadBoards(nooksPath string) (*BoardsFile, error) {
	boardsPath := filepath.Join(nooksPath, "boards.yaml")

	data, err := os.ReadFile(boardsPath)
	if err != nil {
		if os.IsNotExist(err) {
			// Return empty BoardsFile, not an error
			return &BoardsFile{
				Boards: make(map[string][]Pin),
			}, nil
		}
		return nil, &BoardError{
			Code:    "BOARD_READ_FAILED",
			Message: fmt.Sprintf("Failed to read boards.yaml: %v", err),
		}
	}

	var boards map[string][]Pin
	if err := yaml.Unmarshal(data, &boards); err != nil {
		return nil, &BoardError{
			Code:    "BOARD_PARSE_FAILED",
			Message: fmt.Sprintf("Failed to parse boards.yaml: %v", err),
		}
	}

	// Initialize empty map if nil
	if boards == nil {
		boards = make(map[string][]Pin)
	}

	return &BoardsFile{Boards: boards}, nil
}
board.SaveBoards function · go · L70-L145 (76 LOC)
internal/board/board.go
func SaveBoards(nooksPath string, boards *BoardsFile) error {
	boardsPath := filepath.Join(nooksPath, "boards.yaml")

	// Marshal to YAML (just the map, not the wrapper struct)
	data, err := yaml.Marshal(boards.Boards)
	if err != nil {
		return &BoardError{
			Code:    "BOARD_MARSHAL_FAILED",
			Message: fmt.Sprintf("Failed to marshal boards: %v", err),
		}
	}

	// Ensure nooks directory exists
	if err := os.MkdirAll(nooksPath, 0755); err != nil {
		return &BoardError{
			Code:    "BOARD_WRITE_FAILED",
			Message: fmt.Sprintf("Failed to create nooks directory: %v", err),
		}
	}

	// Create temp file in same directory for atomic rename
	tempFile, err := os.CreateTemp(nooksPath, "boards.yaml.tmp.*")
	if err != nil {
		return &BoardError{
			Code:    "BOARD_WRITE_FAILED",
			Message: fmt.Sprintf("Failed to create temp file: %v", err),
		}
	}
	tempPath := tempFile.Name()

	// Ensure temp file cleanup on error
	defer func() {
		if tempPath != "" {
			os.Remove(tempPath)
		}
	}()

	// Write 
board.AddPin function · go · L149-L165 (17 LOC)
internal/board/board.go
func AddPin(boards *BoardsFile, nookID string, content string) string {
	// Initialize boards map if nil
	if boards.Boards == nil {
		boards.Boards = make(map[string][]Pin)
	}

	// Generate RFC3339 timestamp
	ts := time.Now().UTC().Format(time.RFC3339)

	// Append pin to nook's board
	boards.Boards[nookID] = append(boards.Boards[nookID], Pin{
		Ts:      ts,
		Content: content,
	})

	return ts
}
board.GetBoard function · go · L169-L180 (12 LOC)
internal/board/board.go
func GetBoard(boards *BoardsFile, nookID string) []Pin {
	if boards.Boards == nil {
		return []Pin{}
	}

	pins, exists := boards.Boards[nookID]
	if !exists {
		return []Pin{}
	}

	return pins
}
cmd.runBoard function · go · L40-L92 (53 LOC)
internal/cmd/board.go
func runBoard() int {
	// 1. Find treehouse (validates we're in an initialized repo)
	thInfo, err := treehouse.FindTreehouse(".")
	if err != nil {
		thErr, ok := err.(*treehouse.TreehouseError)
		if ok {
			output.PrintError(thErr.Code, thErr.Message)
		} else {
			output.PrintError("INIT_NOT_FOUND", err.Error())
		}
		return 1
	}

	// 2. Get current nook context
	parentInfo, err := worktree.GetParentInfo(thInfo.TreehousePath)
	if err != nil {
		output.PrintError("BOARD_NOT_IN_NOOK", "Must be in a nook to view board")
		return 1
	}

	// 3. Verify we're in a nook
	if !parentInfo.IsNook {
		output.PrintError("BOARD_NOT_IN_NOOK", "Must be in a nook to view board")
		return 1
	}

	nookID := parentInfo.CurrentNook

	// 4. Build nooks path and load boards
	nooksPath := filepath.Join(thInfo.TreehousePath, "nooks")
	boards, err := board.LoadBoards(nooksPath)
	if err != nil {
		boardErr, ok := err.(*board.BoardError)
		if ok {
			output.PrintError(boardErr.Code, boardErr.Message)
		} else {
			
cmd.runFork function · go · L53-L212 (160 LOC)
internal/cmd/fork.go
func runFork(name string) int {
	// 1. Validate nook name
	if err := nook.ValidateName(name); err != nil {
		nookErr, ok := err.(*nook.NookError)
		if ok {
			output.PrintError(nookErr.Code, nookErr.Message)
		} else {
			output.PrintError("NOOK_NAME_INVALID", err.Error())
		}
		return 2
	}

	// 2. Find treehouse (this validates we're in an initialized repo)
	thInfo, err := treehouse.FindTreehouse(".")
	if err != nil {
		thErr, ok := err.(*treehouse.TreehouseError)
		if ok {
			output.PrintError(thErr.Code, thErr.Message)
		} else {
			output.PrintError("INIT_NOT_FOUND", err.Error())
		}
		return 1
	}

	// 3. Get git repo info for commit SHA
	repoInfo, err := git.DetectRepo()
	if err != nil {
		gitErr, ok := err.(*git.GitError)
		if ok {
			output.PrintError(gitErr.Code, gitErr.Message)
			return 3
		}
		output.PrintError("GIT_ERROR", err.Error())
		return 3
	}

	// 3b. Validate commit SHA is present
	if repoInfo.CommitSHA == "" {
		output.PrintError("GIT_NO_COMMITS", "No commits found
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
cmd.setupClaudeCommandsSymlink function · go · L217-L242 (26 LOC)
internal/cmd/fork.go
func setupClaudeCommandsSymlink(repoRoot, nookPath string) error {
	// Check if source exists
	sourcePath := filepath.Join(repoRoot, ".claude", "commands", "th")
	if _, err := os.Stat(sourcePath); os.IsNotExist(err) {
		return nil // th commands don't exist in base repo, skip
	}

	// Create .claude/commands/ directory in nook
	nookCommandsDir := filepath.Join(nookPath, ".claude", "commands")
	if err := os.MkdirAll(nookCommandsDir, 0755); err != nil {
		return fmt.Errorf("failed to create .claude/commands: %w", err)
	}

	// Create relative symlink
	// From: {nook}/.claude/commands/th
	// To:   {repo}/.claude/commands/th
	// Relative: ../../../../../.claude/commands/th
	symlinkPath := filepath.Join(nookCommandsDir, "th")
	relTarget := filepath.Join("..", "..", "..", "..", "..", ".claude", "commands", "th")

	if err := os.Symlink(relTarget, symlinkPath); err != nil {
		return fmt.Errorf("failed to create symlink: %w", err)
	}

	return nil
}
cmd.runHatAdd function · go · L68-L139 (72 LOC)
internal/cmd/hat.go
func runHatAdd(name string, configJSON string) int {
	// 1. Validate name format (lowercase, no special chars except hyphens)
	sanitizedName := sanitizeHatName(name)
	if sanitizedName == "" {
		output.PrintError("HAT_INVALID_NAME", "Invalid hat name: must be lowercase alphanumeric with hyphens only")
		return 2
	}

	// 2. Parse JSON config
	var config HatConfig
	if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
		output.PrintError("HAT_INVALID_CONFIG", fmt.Sprintf("Invalid JSON config: %s", err.Error()))
		return 2
	}

	// 3. Validate required fields
	if err := validateHatConfig(&config); err != nil {
		output.PrintError("HAT_INVALID_CONFIG", err.Error())
		return 2
	}

	// Use sanitized name
	config.Name = sanitizedName

	// Set default icon if not provided
	if config.Icon == "" {
		config.Icon = "◇"
	}

	// 4. Find treehouse (validates we're in an initialized repo)
	thInfo, err := treehouse.FindTreehouse(".")
	if err != nil {
		thErr, ok := err.(*treehouse.Treehouse
cmd.sanitizeHatName function · go · L142-L165 (24 LOC)
internal/cmd/hat.go
func sanitizeHatName(name string) string {
	// Convert to lowercase
	name = strings.ToLower(name)

	// Replace spaces with hyphens
	name = strings.ReplaceAll(name, " ", "-")

	// Remove any character that isn't alphanumeric or hyphen
	var result strings.Builder
	for _, r := range name {
		if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' {
			result.WriteRune(r)
		}
	}

	// Collapse multiple hyphens and trim
	sanitized := result.String()
	for strings.Contains(sanitized, "--") {
		sanitized = strings.ReplaceAll(sanitized, "--", "-")
	}
	sanitized = strings.Trim(sanitized, "-")

	return sanitized
}
cmd.validateHatConfig function · go · L168-L173 (6 LOC)
internal/cmd/hat.go
func validateHatConfig(config *HatConfig) error {
	if config.Title == "" {
		return fmt.Errorf("missing required field: title")
	}
	return nil
}
cmd.createHatFile function · go · L176-L207 (32 LOC)
internal/cmd/hat.go
func createHatFile(treehousePath, name string, config *HatConfig) error {
	hatsDir := filepath.Join(treehousePath, "hats")

	// Ensure hats directory exists
	if err := os.MkdirAll(hatsDir, 0755); err != nil {
		return err
	}

	titleCaser := cases.Title(language.English)
	displayName := titleCaser.String(strings.ReplaceAll(config.Name, "-", " "))
	if config.Name == "" {
		displayName = "Hat"
	}

	hatMD := fmt.Sprintf(`# %s %s

> %s

---

## Domain Knowledge

(Add domain expertise that applies across all nooks)

---

Last Updated: (auto-updated on save)
`, config.Icon, displayName, config.Title)

	hatPath := filepath.Join(hatsDir, name+".md")
	return os.WriteFile(hatPath, []byte(hatMD), 0644)
}
cmd.createHatCommandStub function · go · L210-L237 (28 LOC)
internal/cmd/hat.go
func createHatCommandStub(repoRoot, name, title, icon string) (string, error) {
	// Create directory structure
	commandDir := filepath.Join(repoRoot, ".claude", "commands", "th", "hats")
	if err := os.MkdirAll(commandDir, 0755); err != nil {
		return "", err
	}

	titleCaser := cases.Title(language.English)
	displayName := titleCaser.String(strings.ReplaceAll(name, "-", " "))

	commandMD := fmt.Sprintf(`# %s %s

%s

TREEHOUSE_BASE_WORKSPACE=%s

<hat-loader>
1. Load {BASE_PATH}/.treehouse/hats/%s.md for domain knowledge
</hat-loader>
`, icon, displayName, title, repoRoot, name)

	commandPath := filepath.Join(commandDir, name+".md")
	if err := os.WriteFile(commandPath, []byte(commandMD), 0644); err != nil {
		return "", err
	}

	return commandPath, nil
}
cmd.runInit function · go · L34-L86 (53 LOC)
internal/cmd/init.go
func runInit() int {
	// 1. Validate git repository
	repoInfo, err := git.DetectRepo()
	if err != nil {
		gitErr, ok := err.(*git.GitError)
		if ok {
			output.PrintError(gitErr.Code, gitErr.Message)
			return 3
		}
		output.PrintError("GIT_ERROR", err.Error())
		return 3
	}

	// 2. Check git version
	if err := git.CheckVersion(); err != nil {
		gitErr, ok := err.(*git.GitError)
		if ok {
			output.PrintError(gitErr.Code, gitErr.Message)
			return 3
		}
		output.PrintError("GIT_ERROR", err.Error())
		return 3
	}

	// 3. Check if .treehouse already exists
	treehousePath := filepath.Join(repoInfo.Root, ".treehouse")
	if _, err := os.Stat(treehousePath); err == nil {
		output.PrintError("INIT_ALREADY_EXISTS", "Treehouse already initialized")
		return 1
	}

	// 4. Update .gitignore before creating structure
	gitignoreUpdated, err := updateGitignore(repoInfo.Root)
	if err != nil {
		output.PrintError("INIT_GITIGNORE_FAILED", err.Error())
		return 1
	}

	// 5. Create folder structure
	create
cmd.createTreehouseStructure function · go · L90-L143 (54 LOC)
internal/cmd/init.go
func createTreehouseStructure(basePath string) ([]string, error) {
	created := []string{}

	// Create directories
	dirs := []string{
		basePath,
		filepath.Join(basePath, "nooks"),
		filepath.Join(basePath, "hats"),
		filepath.Join(basePath, "workflows"),
	}

	for _, dir := range dirs {
		if err := os.MkdirAll(dir, 0755); err != nil {
			// Cleanup on failure
			_ = os.RemoveAll(basePath)
			return nil, err
		}
	}

	// Create decks.yaml
	decksPath := filepath.Join(basePath, "decks.yaml")
	if err := os.WriteFile(decksPath, []byte("decks: {}\n"), 0644); err != nil {
		_ = os.RemoveAll(basePath)
		return nil, err
	}
	created = append(created, "decks.yaml")
	created = append(created, "nooks/")
	created = append(created, "hats/")

	// Install workflows from embedded assets
	workflowsPath := filepath.Join(basePath, "workflows")
	installedWorkflows, err := installWorkflows(workflowsPath)
	if err != nil {
		_ = os.RemoveAll(basePath)
		return nil, err
	}
	for _, w := range installedWorkflows {
Want this analysis on your repo? https://repobility.com/scan/
cmd.installWorkflows function · go · L146-L176 (31 LOC)
internal/cmd/init.go
func installWorkflows(destPath string) ([]string, error) {
	installed := []string{}

	// Read workflow files from embedded assets
	entries, err := assets.Workflows.ReadDir("workflows")
	if err != nil {
		return nil, err
	}

	for _, entry := range entries {
		if entry.IsDir() {
			continue // Skip claude/ subdirectory, handled separately
		}
		if filepath.Ext(entry.Name()) != ".md" {
			continue
		}

		content, err := assets.Workflows.ReadFile("workflows/" + entry.Name())
		if err != nil {
			return nil, err
		}

		destFile := filepath.Join(destPath, entry.Name())
		if err := os.WriteFile(destFile, content, 0644); err != nil {
			return nil, err
		}
		installed = append(installed, entry.Name())
	}

	return installed, nil
}
cmd.installClaudeCommands function · go · L180-L216 (37 LOC)
internal/cmd/init.go
func installClaudeCommands(destPath string, repoRoot string) ([]string, error) {
	installed := []string{}

	// Create directory structure
	if err := os.MkdirAll(destPath, 0755); err != nil {
		return nil, err
	}

	// Read Claude command files from embedded assets
	entries, err := assets.Workflows.ReadDir("workflows/claude")
	if err != nil {
		return nil, err
	}

	for _, entry := range entries {
		if entry.IsDir() || filepath.Ext(entry.Name()) != ".md" {
			continue
		}

		content, err := assets.Workflows.ReadFile("workflows/claude/" + entry.Name())
		if err != nil {
			return nil, err
		}

		// Replace placeholder with actual repoRoot path
		contentStr := string(content)
		contentStr = strings.Replace(contentStr, "{{TREEHOUSE_BASE_WORKSPACE}}", repoRoot, -1)

		destFile := filepath.Join(destPath, entry.Name())
		if err := os.WriteFile(destFile, []byte(contentStr), 0644); err != nil {
			return nil, err
		}
		installed = append(installed, entry.Name())
	}

	return installed, nil
}
cmd.updateGitignore function · go · L229-L262 (34 LOC)
internal/cmd/init.go
func updateGitignore(repoRoot string) (bool, error) {
	gitignorePath := filepath.Join(repoRoot, ".gitignore")

	// Check if .gitignore exists
	content, err := os.ReadFile(gitignorePath)
	if err != nil {
		if os.IsNotExist(err) {
			// Create new .gitignore with our block
			if err := os.WriteFile(gitignorePath, []byte(treehouseGitignoreBlock), 0644); err != nil {
				return false, err
			}
			return true, nil
		}
		return false, err
	}

	// Check if treehouse entries already exist
	if containsTreehouseEntries(string(content)) {
		return false, nil // Already present, no update needed
	}

	// Append treehouse block to existing content
	newContent := string(content)
	if len(newContent) > 0 && newContent[len(newContent)-1] != '\n' {
		newContent += "\n"
	}
	newContent += "\n" + treehouseGitignoreBlock

	if err := os.WriteFile(gitignorePath, []byte(newContent), 0644); err != nil {
		return false, err
	}

	return true, nil
}
cmd.containsTreehouseEntries function · go · L265-L275 (11 LOC)
internal/cmd/init.go
func containsTreehouseEntries(content string) bool {
	// Check for the managed marker or the actual entries
	if strings.Contains(content, treehouseGitignoreMarker) {
		return true
	}
	// Also check for the individual entries in case added manually
	if strings.Contains(content, ".treehouse/") && strings.Contains(content, ".claude/commands/th") {
		return true
	}
	return false
}
cmd.runList function · go · L65-L130 (66 LOC)
internal/cmd/list.go
func runList() int {
	// 1. Find treehouse (validates we're in an initialized repo)
	thInfo, err := treehouse.FindTreehouse(".")
	if err != nil {
		thErr, ok := err.(*treehouse.TreehouseError)
		if ok {
			output.PrintError(thErr.Code, thErr.Message)
		} else {
			output.PrintError("INIT_NOT_FOUND", err.Error())
		}
		return 1
	}

	// 2. Load decks
	decksData, err := deck.LoadDecks(thInfo.TreehousePath)
	if err != nil {
		output.PrintError("DECK_LOAD_ERROR", err.Error())
		return 1
	}

	// 3. Get base repository information
	repoInfo, err := git.DetectRepo()
	if err != nil {
		gitErr, ok := err.(*git.GitError)
		if ok {
			output.PrintError(gitErr.Code, gitErr.Message)
			return 3
		}
		output.PrintError("GIT_ERROR", err.Error())
		return 3
	}

	baseInfo := BaseInfo{
		Path:   thInfo.RepoRoot,
		Branch: repoInfo.Branch,
		Commit: repoInfo.CommitSHA, // Already short form (7 chars)
	}

	// 4. Determine current nook
	parentInfo, err := worktree.GetParentInfo(thInfo.TreehousePath)
	if err
cmd.buildDeckResults function · go · L133-L169 (37 LOC)
internal/cmd/list.go
func buildDeckResults(decksData *deck.DecksFile, thInfo *treehouse.Info, currentNook *string) []DeckResult {
	if decksData == nil || len(decksData.Decks) == 0 {
		return []DeckResult{}
	}

	results := make([]DeckResult, 0, len(decksData.Decks))

	for deckID, deckData := range decksData.Decks {
		deckResult := DeckResult{
			ID:      deckID,
			Created: deckData.Created,
			Nooks:   make([]NookResult, 0, len(deckData.Nooks)),
		}

		for nookID, nookData := range deckData.Nooks {
			// Build worktree path
			worktreePath := filepath.Join(thInfo.WorktreesPath, nookID)

			// Determine status
			status := determineNookStatus(nookID, worktreePath, currentNook)

			nookResult := NookResult{
				ID:       nookID,
				Parent:   nookData.Parent,
				Created:  nookData.Created,
				Worktree: worktreePath,
				Status:   status,
			}

			deckResult.Nooks = append(deckResult.Nooks, nookResult)
		}

		results = append(results, deckResult)
	}

	return results
}
cmd.determineNookStatus function · go · L172-L185 (14 LOC)
internal/cmd/list.go
func determineNookStatus(nookID string, worktreePath string, currentNook *string) string {
	// Check if this is the current nook
	if currentNook != nil && *currentNook == nookID {
		return "active"
	}

	// Check if worktree exists
	exists, err := worktree.Exists(worktreePath)
	if err != nil || !exists {
		return "orphan"
	}

	return "inactive"
}
cmd.runPin function · go · L42-L106 (65 LOC)
internal/cmd/pin.go
func runPin(content string) int {
	// 1. Find treehouse (validates we're in an initialized repo)
	thInfo, err := treehouse.FindTreehouse(".")
	if err != nil {
		thErr, ok := err.(*treehouse.TreehouseError)
		if ok {
			output.PrintError(thErr.Code, thErr.Message)
		} else {
			output.PrintError("INIT_NOT_FOUND", err.Error())
		}
		return 1
	}

	// 2. Get current nook context
	parentInfo, err := worktree.GetParentInfo(thInfo.TreehousePath)
	if err != nil {
		output.PrintError("PIN_NOT_IN_NOOK", "Must be in a nook to pin")
		return 1
	}

	// 3. Verify we're in a nook
	if !parentInfo.IsNook {
		output.PrintError("PIN_NOT_IN_NOOK", "Must be in a nook to pin")
		return 1
	}

	nookID := parentInfo.CurrentNook

	// 4. Build nooks path and load boards
	nooksPath := filepath.Join(thInfo.TreehousePath, "nooks")
	boards, err := board.LoadBoards(nooksPath)
	if err != nil {
		boardErr, ok := err.(*board.BoardError)
		if ok {
			output.PrintError(boardErr.Code, boardErr.Message)
		} else {
			output
Repobility (the analyzer behind this table) · https://repobility.com
cmd.runPrune function · go · L42-L144 (103 LOC)
internal/cmd/prune.go
func runPrune() int {
	// 1. Find treehouse
	thInfo, err := treehouse.FindTreehouse(".")
	if err != nil {
		thErr, ok := err.(*treehouse.TreehouseError)
		if ok {
			output.PrintError(thErr.Code, thErr.Message)
		} else {
			output.PrintError("INIT_NOT_FOUND", err.Error())
		}
		return 1
	}

	// 2. Load decks
	decks, err := deck.LoadDecks(thInfo.TreehousePath)
	if err != nil {
		deckErr, ok := err.(*deck.DeckError)
		if ok {
			// If no decks file, nothing to prune
			if deckErr.Code == "DECK_FILE_NOT_FOUND" {
				output.PrintSuccess(PruneResult{
					Pruned:       []string{},
					DecksRemoved: []string{},
				})
				return 0
			}
			output.PrintError(deckErr.Code, deckErr.Message)
		} else {
			output.PrintError("DECK_ERROR", err.Error())
		}
		return 1
	}

	// 3. Find orphaned nooks (entries in decks.yaml with missing worktrees)
	var orphans []string
	for _, d := range decks.Decks {
		if d.Nooks == nil {
			continue
		}
		for nookID := range d.Nooks {
			worktreePath := filepath.Joi
cmd.runRemove function · go · L49-L153 (105 LOC)
internal/cmd/remove.go
func runRemove(nookID string) int {
	// 0. Validate nook ID format (prevents path traversal)
	if err := nook.ValidateNookID(nookID); err != nil {
		nookErr, ok := err.(*nook.NookError)
		if ok {
			output.PrintError(nookErr.Code, nookErr.Message)
		} else {
			output.PrintError("INVALID_NOOK_ID", err.Error())
		}
		return 2
	}

	// 1. Find treehouse
	thInfo, err := treehouse.FindTreehouse(".")
	if err != nil {
		thErr, ok := err.(*treehouse.TreehouseError)
		if ok {
			output.PrintError(thErr.Code, thErr.Message)
		} else {
			output.PrintError("INIT_NOT_FOUND", err.Error())
		}
		return 1
	}

	// 2. Check if trying to remove current nook
	parentInfo, err := worktree.GetParentInfo(thInfo.TreehousePath)
	if err != nil {
		wtErr, ok := err.(*worktree.WorktreeError)
		if ok {
			output.PrintError(wtErr.Code, wtErr.Message)
			return 1
		}
		output.PrintError("WORKTREE_ERROR", err.Error())
		return 1
	}

	if parentInfo.IsNook && parentInfo.CurrentNook == nookID {
		output.PrintError("NOOK_
cmd.collectNooksToRemoveWithDepth function · go · L161-L182 (22 LOC)
internal/cmd/remove.go
func collectNooksToRemoveWithDepth(decks *deck.DecksFile, nookID string, depth int) []string {
	// Prevent stack overflow with depth limit
	if depth >= maxRecursionDepth {
		// Return just this nook if we hit the limit
		return []string{nookID}
	}

	var result []string

	// Get direct children
	children := deck.GetChildNooks(decks, nookID)

	// Recursively collect all descendants (depth-first)
	for _, child := range children {
		result = append(result, collectNooksToRemoveWithDepth(decks, child, depth+1)...)
	}

	// Add this nook last (after all children)
	result = append(result, nookID)

	return result
}
cmd.init function · go · L43-L49 (7 LOC)
internal/cmd/root.go
func init() {
	rootCmd.Flags().BoolVarP(&versionFlag, "version", "v", false, "Print version information")
	// Disable default help flag - we output JSON for everything
	rootCmd.SetHelpFunc(func(cmd *cobra.Command, args []string) {
		output.PrintError("NO_COMMAND", "No command specified. Use a subcommand.")
	})
}
cmd.Execute function · go · L53-L119 (67 LOC)
internal/cmd/root.go
func Execute(args []string) int {
	// Reset version flag and exit codes for each execution (important for tests)
	versionFlag = false
	initExitCode = 0
	listExitCode = 0
	removeExitCode = 0
	pruneExitCode = 0
	hatExitCode = 0
	pinExitCode = 0
	boardExitCode = 0

	rootCmd.SetArgs(args)

	err := rootCmd.Execute()
	if err != nil {
		// Handle unknown flags and other parsing errors
		output.PrintError("INVALID_ARGS", err.Error())
		return 2
	}

	// If version was requested, return success
	if versionFlag {
		return 0
	}

	// If no args provided (no subcommand), return exit code 2
	if len(args) == 0 {
		return 2
	}

	// Check if init command was executed and return its exit code
	if len(args) > 0 && args[0] == "init" {
		return initExitCode
	}

	// Check if list command was executed and return its exit code
	if len(args) > 0 && args[0] == "list" {
		return listExitCode
	}

	// Check if remove command was executed and return its exit code
	if len(args) > 0 && args[0] == "remove" {
		return r
deck.LoadDecks function · go · L39-L70 (32 LOC)
internal/deck/deck.go
func LoadDecks(treehousePath string) (*DecksFile, error) {
	decksPath := filepath.Join(treehousePath, "decks.yaml")

	data, err := os.ReadFile(decksPath)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, &DeckError{
				Code:    "DECK_FILE_NOT_FOUND",
				Message: fmt.Sprintf("decks.yaml not found at %s", decksPath),
			}
		}
		return nil, &DeckError{
			Code:    "DECK_READ_FAILED",
			Message: fmt.Sprintf("Failed to read decks.yaml: %v", err),
		}
	}

	var decksFile DecksFile
	if err := yaml.Unmarshal(data, &decksFile); err != nil {
		return nil, &DeckError{
			Code:    "DECK_PARSE_FAILED",
			Message: fmt.Sprintf("Failed to parse decks.yaml: %v", err),
		}
	}

	// Initialize empty maps if nil
	if decksFile.Decks == nil {
		decksFile.Decks = make(map[string]*Deck)
	}

	return &decksFile, nil
}
deck.NookExists function · go · L73-L92 (20 LOC)
internal/deck/deck.go
func NookExists(treehousePath string, nookID string) (bool, error) {
	decks, err := LoadDecks(treehousePath)
	if err != nil {
		// If decks.yaml doesn't exist, no nooks exist
		if deckErr, ok := err.(*DeckError); ok && deckErr.Code == "DECK_FILE_NOT_FOUND" {
			return false, nil
		}
		return false, err
	}

	for _, deck := range decks.Decks {
		if deck.Nooks != nil {
			if _, exists := deck.Nooks[nookID]; exists {
				return true, nil
			}
		}
	}

	return false, nil
}
deck.GetNook function · go · L95-L113 (19 LOC)
internal/deck/deck.go
func GetNook(treehousePath string, nookID string) (*Nook, string, error) {
	decks, err := LoadDecks(treehousePath)
	if err != nil {
		return nil, "", err
	}

	for deckID, deck := range decks.Decks {
		if deck.Nooks != nil {
			if nook, exists := deck.Nooks[nookID]; exists {
				return nook, deckID, nil
			}
		}
	}

	return nil, "", &DeckError{
		Code:    "NOOK_NOT_FOUND",
		Message: fmt.Sprintf("Nook '%s' not found", nookID),
	}
}
All rows above produced by Repobility · https://repobility.com
deck.SaveDecks function · go · L116-L183 (68 LOC)
internal/deck/deck.go
func SaveDecks(treehousePath string, decks *DecksFile) error {
	decksPath := filepath.Join(treehousePath, "decks.yaml")

	// Marshal to YAML
	data, err := yaml.Marshal(decks)
	if err != nil {
		return &DeckError{
			Code:    "DECK_MARSHAL_FAILED",
			Message: fmt.Sprintf("Failed to marshal decks: %v", err),
		}
	}

	// Create temp file in same directory for atomic rename
	tempFile, err := os.CreateTemp(treehousePath, "decks.yaml.tmp.*")
	if err != nil {
		return &DeckError{
			Code:    "DECK_WRITE_FAILED",
			Message: fmt.Sprintf("Failed to create temp file: %v", err),
		}
	}
	tempPath := tempFile.Name()

	// Ensure temp file cleanup on error
	defer func() {
		if tempPath != "" {
			os.Remove(tempPath)
		}
	}()

	// Write data to temp file
	if _, err := tempFile.Write(data); err != nil {
		tempFile.Close()
		return &DeckError{
			Code:    "DECK_WRITE_FAILED",
			Message: fmt.Sprintf("Failed to write temp file: %v", err),
		}
	}

	// Sync to disk
	if err := tempFile.Sync(); err != nil {
deck.CreateDeck function · go · L192-L197 (6 LOC)
internal/deck/deck.go
func CreateDeck(deckID string, created string) *Deck {
	return &Deck{
		Created: created,
		Nooks:   make(map[string]*Nook),
	}
}
deck.AddNookToDeck function · go · L201-L226 (26 LOC)
internal/deck/deck.go
func AddNookToDeck(decks *DecksFile, deckID string, nookID string, parent string, created string) string {
	// Initialize decks map if nil
	if decks.Decks == nil {
		decks.Decks = make(map[string]*Deck)
	}

	// Create deck if it doesn't exist
	deck, exists := decks.Decks[deckID]
	if !exists {
		deck = CreateDeck(deckID, created)
		decks.Decks[deckID] = deck
	}

	// Initialize nooks map if nil
	if deck.Nooks == nil {
		deck.Nooks = make(map[string]*Nook)
	}

	// Add the nook
	deck.Nooks[nookID] = &Nook{
		Parent:  parent,
		Created: created,
	}

	return deckID
}
deck.RemoveNook function · go · L230-L252 (23 LOC)
internal/deck/deck.go
func RemoveNook(decks *DecksFile, deckID string, nookID string) (bool, error) {
	deck, exists := decks.Decks[deckID]
	if !exists {
		return false, &DeckError{
			Code:    "DECK_NOT_FOUND",
			Message: fmt.Sprintf("Deck '%s' not found", deckID),
		}
	}

	if deck.Nooks == nil {
		return true, nil
	}

	delete(deck.Nooks, nookID)

	// Check if deck is now empty
	if len(deck.Nooks) == 0 {
		delete(decks.Decks, deckID)
		return true, nil
	}

	return false, nil
}
deck.GetDeckForNook function · go · L255-L264 (10 LOC)
internal/deck/deck.go
func GetDeckForNook(decks *DecksFile, nookID string) (string, bool) {
	for deckID, deck := range decks.Decks {
		if deck.Nooks != nil {
			if _, exists := deck.Nooks[nookID]; exists {
				return deckID, true
			}
		}
	}
	return "", false
}
deck.GetChildNooks function · go · L267-L279 (13 LOC)
internal/deck/deck.go
func GetChildNooks(decks *DecksFile, parentNookID string) []string {
	var children []string
	for _, deck := range decks.Decks {
		if deck.Nooks != nil {
			for nookID, nook := range deck.Nooks {
				if nook.Parent == parentNookID {
					children = append(children, nookID)
				}
			}
		}
	}
	return children
}
git.DetectRepo function · go · L41-L74 (34 LOC)
internal/git/detect.go
func DetectRepo() (*RepoInfo, error) {
	// Check if inside git repo and get root
	rootOut, err := exec.Command("git", "rev-parse", "--show-toplevel").Output()
	if err != nil {
		return nil, &GitError{
			Code:    "INIT_NOT_GIT_REPO",
			Message: "Not a git repository",
		}
	}

	// Get current branch
	branchOut, err := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD").Output()
	if err != nil {
		return nil, &GitError{
			Code:    "GIT_BRANCH_ERROR",
			Message: fmt.Sprintf("Failed to get branch: %v", err),
		}
	}

	// Get commit SHA (first 7 characters)
	shaOut, err := exec.Command("git", "rev-parse", "--short=7", "HEAD").Output()
	if err != nil {
		return nil, &GitError{
			Code:    "GIT_SHA_ERROR",
			Message: fmt.Sprintf("Failed to get commit SHA: %v", err),
		}
	}

	return &RepoInfo{
		Root:      strings.TrimSpace(string(rootOut)),
		Branch:    strings.TrimSpace(string(branchOut)),
		CommitSHA: strings.TrimSpace(string(shaOut)),
	}, nil
}
git.CheckVersion function · go · L79-L97 (19 LOC)
internal/git/detect.go
func CheckVersion() error {
	output, err := exec.Command("git", "--version").Output()
	if err != nil {
		return &GitError{
			Code:    "GIT_NOT_FOUND",
			Message: "Git not installed",
		}
	}

	version, err := parseVersion(string(output))
	if err != nil {
		return &GitError{
			Code:    "GIT_VERSION_PARSE_ERROR",
			Message: fmt.Sprintf("Failed to parse git version: %v", err),
		}
	}

	return checkVersionRequirement(version)
}
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
git.parseVersion function · go · L101-L129 (29 LOC)
internal/git/detect.go
func parseVersion(versionStr string) (Version, error) {
	// Use pre-compiled regex with optional patch version
	matches := versionRegex.FindStringSubmatch(versionStr)

	if len(matches) < 3 {
		return Version{}, fmt.Errorf("invalid git version format: %s", versionStr)
	}

	major, err := strconv.Atoi(matches[1])
	if err != nil {
		return Version{}, fmt.Errorf("invalid major version: %v", err)
	}

	minor, err := strconv.Atoi(matches[2])
	if err != nil {
		return Version{}, fmt.Errorf("invalid minor version: %v", err)
	}

	// Patch is optional (some git versions report only major.minor)
	var patch int
	if len(matches) > 3 && matches[3] != "" {
		patch, err = strconv.Atoi(matches[3])
		if err != nil {
			return Version{}, fmt.Errorf("invalid patch version: %v", err)
		}
	}

	return Version{Major: major, Minor: minor, Patch: patch}, nil
}
git.checkVersionRequirement function · go · L132-L141 (10 LOC)
internal/git/detect.go
func checkVersionRequirement(v Version) error {
	// Git 2.5+ is required for worktree support
	if v.Major < 2 || (v.Major == 2 && v.Minor < 5) {
		return &GitError{
			Code:    "GIT_VERSION_UNSUPPORTED",
			Message: "Git 2.5+ required for worktree support",
		}
	}
	return nil
}
nook.GenerateID function · go · L30-L48 (19 LOC)
internal/nook/nook.go
func GenerateID(name string, commitSHA string) (string, error) {
	if len(commitSHA) < 4 {
		return "", &NookError{
			Code:    "NOOK_INVALID_SHA",
			Message: "Commit SHA must be at least 4 characters",
		}
	}

	sanitized := SanitizeName(name)
	if sanitized == "" {
		return "", &NookError{
			Code:    "NOOK_NAME_INVALID",
			Message: "Nook name cannot be empty or contain only special characters",
		}
	}

	hash := strings.ToLower(commitSHA[:4])
	return fmt.Sprintf("%s-%s", hash, sanitized), nil
}
nook.SanitizeName function · go · L57-L74 (18 LOC)
internal/nook/nook.go
func SanitizeName(name string) string {
	// Step 1: Convert to lowercase
	result := strings.ToLower(name)

	// Step 2: Replace spaces with hyphens
	result = strings.ReplaceAll(result, " ", "-")

	// Step 3: Remove non-alphanumeric characters (except hyphens)
	result = nonAlphanumericRegex.ReplaceAllString(result, "")

	// Step 4: Collapse multiple consecutive hyphens
	result = multipleHyphensRegex.ReplaceAllString(result, "-")

	// Step 5: Trim leading/trailing hyphens
	result = strings.Trim(result, "-")

	return result
}
nook.ValidateName function · go · L77-L86 (10 LOC)
internal/nook/nook.go
func ValidateName(name string) error {
	sanitized := SanitizeName(name)
	if sanitized == "" {
		return &NookError{
			Code:    "NOOK_NAME_INVALID",
			Message: "Nook name cannot be empty or contain only special characters",
		}
	}
	return nil
}
nook.ParseNookID function · go · L90-L117 (28 LOC)
internal/nook/nook.go
func ParseNookID(nookID string) (hash string, name string, err error) {
	if len(nookID) < 6 { // minimum: 4-char hash + hyphen + 1-char name
		return "", "", &NookError{
			Code:    "NOOK_ID_INVALID",
			Message: fmt.Sprintf("Invalid nook ID format: %s", nookID),
		}
	}

	// Find the first hyphen after the 4-char hash
	if nookID[4] != '-' {
		return "", "", &NookError{
			Code:    "NOOK_ID_INVALID",
			Message: fmt.Sprintf("Invalid nook ID format: %s", nookID),
		}
	}

	hash = nookID[:4]
	name = nookID[5:]

	if name == "" {
		return "", "", &NookError{
			Code:    "NOOK_ID_INVALID",
			Message: fmt.Sprintf("Invalid nook ID format: %s", nookID),
		}
	}

	return hash, name, nil
}
nook.ValidateNookID function · go · L124-L150 (27 LOC)
internal/nook/nook.go
func ValidateNookID(nookID string) error {
	// Check minimum length
	if len(nookID) < 6 {
		return &NookError{
			Code:    "INVALID_NOOK_ID",
			Message: fmt.Sprintf("Invalid nook ID format: %s", nookID),
		}
	}

	// Check for path traversal attempts
	if strings.Contains(nookID, "..") || strings.Contains(nookID, "/") || strings.Contains(nookID, "\\") {
		return &NookError{
			Code:    "INVALID_NOOK_ID",
			Message: fmt.Sprintf("Invalid nook ID: contains illegal characters: %s", nookID),
		}
	}

	// Validate format with regex
	if !nookIDRegex.MatchString(nookID) {
		return &NookError{
			Code:    "INVALID_NOOK_ID",
			Message: fmt.Sprintf("Invalid nook ID format: %s", nookID),
		}
	}

	return nil
}
output.PrintError function · go · L38-L44 (7 LOC)
internal/output/json.go
func PrintError(code, message string) {
	resp := Response{
		Success: false,
		Error:   &ErrorInfo{Code: code, Message: message},
	}
	printJSON(resp)
}
Want this analysis on your repo? https://repobility.com/scan/
output.printJSON function · go · L47-L54 (8 LOC)
internal/output/json.go
func printJSON(v interface{}) {
	bytes, err := json.Marshal(v)
	if err != nil {
		// Fallback to a valid error JSON if marshal fails
		bytes = []byte(`{"success":false,"error":{"code":"MARSHAL_ERROR","message":"failed to marshal response"}}`)
	}
	fmt.Fprintln(writer, string(bytes))
}
testutil.SetupGitRepo function · go · L13-L56 (44 LOC)
internal/testutil/git.go
func SetupGitRepo(t *testing.T) string {
	t.Helper()
	dir := t.TempDir()

	// Initialize git repo
	cmd := exec.Command("git", "init")
	cmd.Dir = dir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to init git repo: %v", err)
	}

	// Configure git user for commits
	cmd = exec.Command("git", "config", "user.email", "[email protected]")
	cmd.Dir = dir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to config git email: %v", err)
	}

	cmd = exec.Command("git", "config", "user.name", "Test User")
	cmd.Dir = dir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to config git name: %v", err)
	}

	// Create initial commit so HEAD exists
	testFile := filepath.Join(dir, "test.txt")
	if err := os.WriteFile(testFile, []byte("test"), 0644); err != nil {
		t.Fatalf("failed to create test file: %v", err)
	}

	cmd = exec.Command("git", "add", ".")
	cmd.Dir = dir
	if err := cmd.Run(); err != nil {
		t.Fatalf("failed to git add: %v", err)
	}

	cmd = exec.Command("git", "commit", "-m", "initi
testutil.ChdirWithCleanup function · go · L60-L71 (12 LOC)
internal/testutil/git.go
func ChdirWithCleanup(t *testing.T, dir string) {
	t.Helper()
	oldWd, err := os.Getwd()
	if err != nil {
		t.Fatalf("failed to get working directory: %v", err)
	}
	t.Cleanup(func() { _ = os.Chdir(oldWd) })

	if err := os.Chdir(dir); err != nil {
		t.Fatalf("failed to change to directory %s: %v", dir, err)
	}
}
page 1 / 2next ›