Skip to content

chore: rolling promotion dev -> main - #650

Merged
namastex888 merged 16 commits into
mainfrom
dev
Mar 18, 2026
Merged

namastex888 merged 16 commits into
mainfrom
dev

Conversation

@namastex888

@namastex888 namastex888 commented Mar 17, 2026 •

Copy link
Copy Markdown
Contributor

Rolling Promotion PR

Auto-maintained rolling promotion PR from dev to main.

Process:

  • This PR is automatically created and kept open
  • Human reviews and merges when ready
  • Label ready-to-merge added when all checks pass

IMPORTANT: Merge with "Create a merge commit" — NEVER squash.
Squash merging breaks history sync between dev and main,
causing the next rolling PR to show all commits again.

Human approval required for merge to production.

Summary by CodeRabbit

  • Chores

    • Version bumped to 3.260317.20 across components
    • TMUX scripts and configuration are synced and auto-reloaded during updates
  • New Features

    • Bottom status bar with clickable tabs, new navigation keybindings, and double-click picker
    • Per-window enrichment labels showing task counts and status icons
    • Formatted session list for the status bar
  • Improvements

    • Smarter session overflow preserving the active session
    • More reliable session/window naming, focus, and resume behavior
    • Team-lead agent defaults and optional session naming flag
  • Tests

    • Updated tests to reflect team-lead naming and clone-based workflows

@coderabbitai

coderabbitai Bot commented Mar 17, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Bumps package/plugin versions to 3.260317.20, adds/updates tmux integration scripts and config, syncs tmux assets from the update command, shifts session naming and agent identity to a team-lead model, and replaces git worktree workflows with shared clone logic.

Changes

Cohort / File(s) Summary
Version bump
\.claude-plugin/marketplace.json, openclaw.plugin.json, package.json, plugins/genie/.claude-plugin/plugin.json, plugins/genie/package.json
All version fields updated from 3.260317.18 → 3.260317.20.
Tmux session rendering
scripts/tmux/genie-projects.sh
Rewrote rendering to merge tmux sessions + workers.json into all_sessions, add max_visible overflow path, preserve active session, and append an overflow indicator.
Tmux window enrichment
scripts/tmux/genie-window-label.sh
New script: single jq query against workers.json to count matching workers and select worst-state emoji; prints " × " or nothing; exits cleanly on missing data.
Tmux sessions list
scripts/tmux/genie-sessions.sh
New script that emits a formatted/styled list of tmux sessions, highlighting the current session.
Tmux configuration
scripts/tmux/genie.tmux.conf
Reworked status layout and styling, moved to single bottom status bar, adjusted left/right sections and activity indicator, added new keybindings (new window, client switching, direct window selects, double-click picker).
Update/sync flow
src/genie-commands/update.ts
Adds tmux asset syncing: copy genie.tmux.conf and tmux scripts, set permissions (0o755 for .sh), detect/manage genie-managed tmux conf header, and attempt non-fatal tmux reload after sync.
Session creation & runtime
src/genie-commands/session.ts, src/genie-commands/__tests__/session.test.ts
Default session naming now uses sanitized workspace basename; native Claude leader agentType set to team-lead; attach/focus windows immediately; run Claude Code synchronously in-pane when inside tmux; tests updated to expect team-lead.
Spawn params & team-lead command
src/lib/provider-adapters.ts, src/lib/team-lead-command.ts, src/term-commands/agents.ts
Added optional name?: string to SpawnParams and emit --name when present; team-lead uses fixed --agent-name team-lead, --agent-id team-lead@..., and --agent-type team-lead; default worker session naming set to team-<effectiveRole> if name missing.
Worktree → shared clone refactor
src/lib/team-manager.ts, src/lib/team-manager.test.ts, src/term-commands/ship.test.ts
Replaced git worktree usage with shared clone approach (clone --shared), updated creation/prune/disband flows and tests, and adjusted pruneStaleWorktrees signature to accept a renamed/unused repo param.
Minor / doc/test
src/genie.ts, assorted tests
Safety comment clarified; tests and docs updated to reflect shared-clone workflow.

Sequence Diagram(s)

sequenceDiagram
    participant Tmux as Tmux
    participant GProj as genie-projects.sh
    participant GLabel as genie-window-label.sh
    participant GSessions as genie-sessions.sh
    participant Workers as workers.json
    participant Update as src/genie-commands/update.ts
    participant Display as TmuxStatus

    Tmux->>GProj: Request render session list
    GProj->>Workers: Read and merge sessions (tmux + workers.json)
    GProj->>GProj: Build all_sessions, decide full vs overflow
    alt total ≤ max_visible
        GProj->>Display: Render all sessions (with labels)
    else total > max_visible
        GProj->>Display: Render up to max_visible (reserve/ensure active)
        GProj->>Display: Append overflow indicator (+N)
    end

    Tmux->>GLabel: Query(session,window) for enrichment
    GLabel->>Workers: Filter & compute count/worst-state
    GLabel-->>Display: " ×<count> <emoji>" or nothing

    Tmux->>GSessions: Request formatted session list
    GSessions-->>Display: Styled session list (highlights active)

    Update->>Tmux: After syncing tmux assets, attempt tmux reload (non-fatal)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'chore: rolling promotion dev -> main' accurately describes the PR's purpose as an automated rolling promotion between branches, which aligns with the commit messages and objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request facilitates the automated promotion of the 'genie' plugin, specifically updating its version across various configuration and package manifest files. It is a routine part of the continuous integration and deployment pipeline, ensuring that the main branch reflects the latest stable dev changes after human review and approval, while adhering to a specific merge strategy to preserve repository history.

Highlights

  • Version Bump: The version of the 'genie' plugin and related packages has been updated from 3.260317.18 to 3.260317.20 across all relevant configuration and package files.
  • Automated Promotion: This pull request is part of an automated rolling promotion process, moving changes from the dev branch to main.
  • Merge Strategy: Reviewers are explicitly instructed to merge this PR using 'Create a merge commit' and to never squash, to maintain proper history synchronization between dev and main.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is an automated rolling promotion from the dev branch to main. The changes consist of version bumps across several package and plugin configuration files. While the version updates are consistent, I've identified a potential point of fragility in the versioning script's logic for updating the marketplace manifest, which could be made more robust to prevent future issues.

Comment thread .claude-plugin/marketplace.json Outdated
{
"name": "genie",
"version": "3.260317.18",
"version": "3.260317.20",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The versioning script (scripts/version.ts) updates this version by targeting the first plugin in the plugins array (plugins[0]). This approach is brittle and may lead to incorrect versioning if more plugins are added to this file or if their order changes. To make the update process more robust, the script should be modified to locate the 'genie' plugin by its name property before updating the version.

Genie and others added 4 commits March 17, 2026 21:07
…chment

Fix broken awk $1/$2 escaping in version guard that prevented dual bar
from activating. Replace genie-tasks.sh script call in status-format[1]
with native #{W} token for clickable window tabs. Add per-window agent
enrichment via genie-window-label.sh called from window-status-format
templates. Add overflow handling to genie-projects.sh for >8 sessions.
fix(tmux): restore dual status bar with clickable tabs and agent enrichment
syncTmuxScripts now also copies genie.tmux.conf to ~/.genie/scripts/,
overwrites ~/.tmux.conf when it contains the genie header, and reloads
tmux automatically. Extracted syncTmuxConf helper to keep complexity
within lint limits.
fix(tmux): sync genie.tmux.conf and auto-reload on update

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/tmux/genie-projects.sh`:
- Line 47: Remove the dead variable assignment and any writes to it: delete the
`active_output=""` initialization and the other write at the second occurrence
(around the other mentioned line) so the first tmux pass only populates
`all_sessions` without introducing unused state; search for the symbol
`active_output` and remove those lines (and any associated, now-unused
references) to avoid writing an unused path.
- Around line 95-100: The reservation logic incorrectly reserves the last slot
even when active_session is empty; update the conditional that currently checks
shown, active_shown, and session_name != active_session to also require that
active_session is non-empty (e.g., test -n "$active_session" or
"$active_session" != ""), so the "reserve last slot for active session" branch
only runs when an active session exists; apply the same change to the other
occurrence that mirrors this logic (the block around the second instance at
lines referenced in the comment).

In `@scripts/tmux/genie.tmux.conf`:
- Around line 83-86: The tmux status formats call the external script via #()
with unescaped format variables (see window-status-format and
window-status-current-format using #{session_name} and #{window_name}), which
can break when names contain spaces or shell metacharacters; update both formats
to use the tmux format-escape modifier #{q:...} for those variables (i.e.,
replace #{session_name} and #{window_name} with #{q:session_name} and
#{q:window_name}) so the arguments are safely quoted when invoking
$HOME/.genie/scripts/genie-window-label.sh.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b68d45ce-fc00-4140-878f-4550ce388efd

📥 Commits

Reviewing files that changed from the base of the PR and between 2b17039 and 931ea45.

📒 Files selected for processing (8)
  • .claude-plugin/marketplace.json
  • openclaw.plugin.json
  • package.json
  • plugins/genie/.claude-plugin/plugin.json
  • plugins/genie/package.json
  • scripts/tmux/genie-projects.sh
  • scripts/tmux/genie-window-label.sh
  • scripts/tmux/genie.tmux.conf

output=""
declare -A seen_sessions=()
declare -a all_sessions=()
active_output=""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove the dead active_output path.

active_output is written once and never read, so this first tmux pass looks stateful when it only populates all_sessions.

Also applies to: 60-60

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/tmux/genie-projects.sh` at line 47, Remove the dead variable
assignment and any writes to it: delete the `active_output=""` initialization
and the other write at the second occurrence (around the other mentioned line)
so the first tmux pass only populates `all_sessions` without introducing unused
state; search for the symbol `active_output` and remove those lines (and any
associated, now-unused references) to avoid writing an unused path.

Comment on lines +95 to +100
if [[ "$shown" -ge "$((max_visible - 1))" && "$active_shown" == "false" && "$session_name" != "$active_session" ]]; then
# Reserve last slot for active session
continue
fi
if [[ "$shown" -ge "$max_visible" ]]; then
break

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Don't reserve an active-session slot when active_session is empty.

In the no-tmux/testing path, active_session stays empty. Once shown reaches 7, this guard skips every remaining session, so you render only 7 entries while +N more is still computed as if 8 were shown.

Suggested fix
-    if [[ "$shown" -ge "$((max_visible - 1))" && "$active_shown" == "false" && "$session_name" != "$active_session" ]]; then
+    if [[ -n "$active_session" && "$shown" -ge "$((max_visible - 1))" && "$active_shown" == "false" && "$session_name" != "$active_session" ]]; then
       # Reserve last slot for active session
       continue
     fi

Also applies to: 128-130

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/tmux/genie-projects.sh` around lines 95 - 100, The reservation logic
incorrectly reserves the last slot even when active_session is empty; update the
conditional that currently checks shown, active_shown, and session_name !=
active_session to also require that active_session is non-empty (e.g., test -n
"$active_session" or "$active_session" != ""), so the "reserve last slot for
active session" branch only runs when an active session exists; apply the same
change to the other occurrence that mirrors this logic (the block around the
second instance at lines referenced in the comment).

Comment thread scripts/tmux/genie.tmux.conf Outdated
Comment on lines +83 to +86
set -g window-status-format "#[fg=#b8a9c9,bg=#16213e] #I:#W#($HOME/.genie/scripts/genie-window-label.sh #{session_name} #{window_name}) "

# Active tab: purple bg, white text, bold
set -g window-status-current-format "#[fg=#1a1a2e,bg=#7b2ff7]#[fg=#e0e0e0,bg=#7b2ff7,bold] #I:#W #[fg=#7b2ff7,bg=#1a1a2e]"
# Active tab: purple bg, white text, bold with agent enrichment
set -g window-status-current-format "#[fg=#16213e,bg=#7b2ff7]#[fg=#e0e0e0,bg=#7b2ff7,bold] #I:#W#($HOME/.genie/scripts/genie-window-label.sh #{session_name} #{window_name}) #[fg=#7b2ff7,bg=#16213e]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In tmux #(...)command substitutions, what is the recommended way to shell-escape#{session_name}and#{window_name} or pass them as positional arguments so spaces and shell metacharacters are preserved safely?

💡 Result:

The recommended way to safely pass tmux format variables like #{session_name} and #{window_name} to shell commands in #(shell-command) substitutions, preserving spaces and shell metacharacters, is to use the #{q:variable} format modifier. This modifier quotes the variable for safe use in shell commands by escaping special characters (e.g., wrapping in single quotes and escaping internal single quotes). For example, in a status line or run-shell command: status-right "#(my-script '#{q:session_name}' '#{q:window_name}')" This expands #{session_name} and #{window_name} safely before passing to the shell command inside #. If passing as positional arguments to a script, the script receives them as argv[1], argv[2], etc., with original content preserved (spaces intact, metacharacters escaped for shell parsing). Alternative for complex cases: Use display-message -p '#{session_name}' in a wrapper script to retrieve values safely via stdout, avoiding direct substitution. tmux does not automatically shell-escape plain #{variable}; using #{q:} is the official recommended approach per tmux source discussions and format documentation.

Citations:


🏁 Script executed:

cat -n scripts/tmux/genie.tmux.conf | sed -n '80,90p'

Repository: automagik-dev/genie

Length of output: 728


Use #{q:...} to safely escape tmux format variables in shell commands.

Lines 83 and 86 pass #{session_name} and #{window_name} unescaped into a shell command via #(). Names with spaces will split the argv; shell metacharacters can be evaluated on every refresh. Use the #{q:variable} format modifier to escape these safely:

set -g window-status-format "#[fg=#b8a9c9,bg=#16213e] `#I`:`#W`#($HOME/.genie/scripts/genie-window-label.sh #{q:session_name} #{q:window_name}) "
set -g window-status-current-format "#[fg=#16213e,bg=#7b2ff7]#[fg=#e0e0e0,bg=#7b2ff7,bold] `#I`:`#W`#($HOME/.genie/scripts/genie-window-label.sh #{q:session_name} #{q:window_name}) #[fg=#7b2ff7,bg=#16213e]"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/tmux/genie.tmux.conf` around lines 83 - 86, The tmux status formats
call the external script via #() with unescaped format variables (see
window-status-format and window-status-current-format using #{session_name} and
#{window_name}), which can break when names contain spaces or shell
metacharacters; update both formats to use the tmux format-escape modifier
#{q:...} for those variables (i.e., replace #{session_name} and #{window_name}
with #{q:session_name} and #{q:window_name}) so the arguments are safely quoted
when invoking $HOME/.genie/scripts/genie-window-label.sh.

Genie added 3 commits March 17, 2026 23:34
# Conflicts:
#	.claude-plugin/marketplace.json
#	openclaw.plugin.json
#	package.json
#	plugins/genie/.claude-plugin/plugin.json
#	plugins/genie/package.json
#	scripts/tmux/genie-projects.sh
#	scripts/tmux/genie.tmux.conf
- Session name derived from folder name (not hardcoded 'genie')
- Running genie in tmux tab launches CC in current pane, not new window
- agentType set to 'team-lead' for self-approval authority
- Bottom bar shows all sessions as "Agents:" via pane-border
- Ctrl+T opens new tab with session start directory
- Ctrl+(/Ctrl+) switches sessions
- Added name field to SpawnParams — sets CC session display name
- buildClaudeCommand() emits --name <name> when provided
- Team-lead command builder passes --name <teamName>
- Worker spawn sets name to <team>-<role> (e.g., fix-parser-engineer-1)
- resume field accepts strings (not just UUIDs) for name-based resume

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
scripts/tmux/genie.tmux.conf (1)

85-85: ⚠️ Potential issue | 🟠 Major

Shell-escape #{session_name} in the #() command.

Line 85 passes #{session_name} unescaped into shell execution. Session names with spaces/metacharacters can break argument parsing or execute unintended shell syntax.

Suggested fix
-set -g pane-border-format "#[align=left,bg=#16213e,fg=#b8a9c9] Agents: #($HOME/.genie/scripts/genie-sessions.sh #{session_name})"
+set -g pane-border-format "#[align=left,bg=#16213e,fg=#b8a9c9] Agents: #($HOME/.genie/scripts/genie-sessions.sh #{q:session_name})"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/tmux/genie.tmux.conf` at line 85, The pane-border-format currently
injects raw #{session_name} into a shell command which can break or allow
injection; change the command so the session name is shell-escaped when invoking
.genie/scripts/genie-sessions.sh (e.g. use tmux's shell-escape format modifier
for the session name such as "#{session_name@sh}" or similar supported :sh
modifier) so the line calling genie-sessions.sh passes a quoted/escaped argument
(reference symbols: pane-border-format, #{session_name}, and
.genie/scripts/genie-sessions.sh).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/tmux/genie-sessions.sh`:
- Around line 11-17: The loop over tmux sessions is splitting session names on
whitespace because it uses for sess in $(tmux list-sessions ...); to fix this,
read the session names line-by-line instead (e.g., pipe tmux list-sessions -F
'#{session_name}' ... | sort into a while IFS= read -r sess loop or use mapfile
-t and iterate the array) so the variable sess preserves spaces and special
characters; update the block that references sess, current_session and appends
to output accordingly to use the line-oriented reader.

In `@src/genie-commands/session.ts`:
- Line 323: The fallback for sessionName currently uses
sanitizeWindowName(basename(workspaceDir)) which creates per-folder sessions;
change the expression so options.name falls back to the existing shared tmux
session constant used elsewhere (instead of basename(workspaceDir)). Edit the
assignment to sessionName (the line using options.name ?? ...) to use that
shared session constant as the default, removing the
sanitizeWindowName(basename(workspaceDir)) fallback to restore the single shared
session behavior.
- Around line 339-347: The inside-tmux branch must use the canonical
deriveWindowName and same registration/env setup as other flows instead of
renaming the current client window with a timestamp suffix; replace the
suffix/currentWindowName logic with a call to deriveWindowName(sessionName?) to
produce the authoritative windowName, remove the ad-hoc Date.now suffix, call
ensureNativeTeamForLeader(derivedWindowName, workspaceDir) and compute
resumeSessionId via findLastSessionId(sanitizeTeamName(derivedWindowName),
agentName, workspaceDir), and ensure the GENIE_CWD window env and registry
registration steps used by other startup paths are executed before building the
command (buildClaudeCommand) so the inside-tmux path remains deterministic and
resumes the correct team/session.
- Around line 348-349: The code uses a runtime require to get execSync which
fails in ESM; instead add a static import for execSync from 'node:child_process'
alongside the existing imports at the top of the file, remove the require(...)
at the call site, and call execSync(cmd, { stdio: 'inherit', cwd: workspaceDir
}) directly where execSyncCmd is currently used (referencing execSync, cmd, and
workspaceDir to find the call).

---

Duplicate comments:
In `@scripts/tmux/genie.tmux.conf`:
- Line 85: The pane-border-format currently injects raw #{session_name} into a
shell command which can break or allow injection; change the command so the
session name is shell-escaped when invoking .genie/scripts/genie-sessions.sh
(e.g. use tmux's shell-escape format modifier for the session name such as
"#{session_name@sh}" or similar supported :sh modifier) so the line calling
genie-sessions.sh passes a quoted/escaped argument (reference symbols:
pane-border-format, #{session_name}, and .genie/scripts/genie-sessions.sh).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7badd5b1-b42a-4be9-b9bb-48a07ed76d15

📥 Commits

Reviewing files that changed from the base of the PR and between f63dd23 and 925dc5b.

📒 Files selected for processing (3)
  • scripts/tmux/genie-sessions.sh
  • scripts/tmux/genie.tmux.conf
  • src/genie-commands/session.ts

Comment on lines +11 to +17
for sess in $(tmux list-sessions -F '#{session_name}' 2>/dev/null | sort); do
if [ "$sess" = "$current_session" ]; then
output+="#[bg=#7b2ff7,fg=#e0e0e0,bold] $sess #[bg=#16213e,fg=#7b2ff7,nobold]"
else
output+="#[fg=#b8a9c9,bg=#16213e] $sess "
fi
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd -t f genie-sessions.sh

Repository: automagik-dev/genie

Length of output: 93


🏁 Script executed:

file_path=$(fd -t f genie-sessions.sh 2>/dev/null | head -1)
if [ -n "$file_path" ]; then
  echo "File found: $file_path"
  wc -l "$file_path"
  head -30 "$file_path" | cat -n
fi

Repository: automagik-dev/genie

Length of output: 839


🌐 Web query:

tmux session names allowed characters spaces special characters constraints

💡 Result:

Tmux session names must be non-empty and cannot contain the characters ':' or '.'. Spaces and other special characters are allowed as long as they are not ':' or '.'. There is no defined maximum length. When creating or renaming a session, tmux validates the name using session_check_name, which returns an error if the name is empty or contains ':' or '.'. In the source code, this check is: return (*name != '\0' && name[strcspn(name, ":.")] == '\0');. If invalid, commands like new-session or rename-session report "bad session name". Colons and periods are prohibited because they are special characters used in tmux targets to separate session:window and window.pane (e.g., mysession:mywindow.1). Tabs are allowed in older versions but sanitized to spaces in tmux 3.2+. Control characters may cause issues like hanging (fixed in 3.0+), but are not explicitly forbidden beyond validation. Examples: - Valid: "my session", "test-123", "user@host" - Invalid: "", "my:session", "my.session", "session:name" Official tmux man pages do not explicitly document these constraints, but they are enforced in the code and confirmed by tmux maintainer in GitHub issues.

Citations:


Avoid word-splitting session names during iteration.

Line 11 uses command substitution in a for loop, which breaks on whitespace in session names and can render incorrect labels.

Suggested fix
 output=""
-for sess in $(tmux list-sessions -F '#{session_name}' 2>/dev/null | sort); do
+while IFS= read -r sess; do
   if [ "$sess" = "$current_session" ]; then
     output+="#[bg=#7b2ff7,fg=#e0e0e0,bold] $sess #[bg=#16213e,fg=#7b2ff7,nobold]"
   else
     output+="#[fg=#b8a9c9,bg=#16213e] $sess "
   fi
-done
+done < <(tmux list-sessions -F '#{session_name}' 2>/dev/null | sort)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/tmux/genie-sessions.sh` around lines 11 - 17, The loop over tmux
sessions is splitting session names on whitespace because it uses for sess in
$(tmux list-sessions ...); to fix this, read the session names line-by-line
instead (e.g., pipe tmux list-sessions -F '#{session_name}' ... | sort into a
while IFS= read -r sess loop or use mapfile -t and iterate the array) so the
variable sess preserves spaces and special characters; update the block that
references sess, current_session and appends to output accordingly to use the
line-oriented reader.

export async function sessionCommand(options: SessionOptions = {}): Promise<void> {
const sessionName = options.name ?? DEFAULT_SESSION_NAME;
const workspaceDir = options.dir ?? process.cwd();
const sessionName = options.name ?? sanitizeWindowName(basename(workspaceDir));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Revert default sessionName to the shared constant.

Defaulting to basename(workspaceDir) shifts behavior from one shared tmux session to per-folder sessions, which conflicts with this command’s documented session model and changes reset/window-collision semantics.

Proposed fix
-  const sessionName = options.name ?? sanitizeWindowName(basename(workspaceDir));
+  const sessionName = options.name ?? DEFAULT_SESSION_NAME;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const sessionName = options.name ?? sanitizeWindowName(basename(workspaceDir));
const sessionName = options.name ?? DEFAULT_SESSION_NAME;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/genie-commands/session.ts` at line 323, The fallback for sessionName
currently uses sanitizeWindowName(basename(workspaceDir)) which creates
per-folder sessions; change the expression so options.name falls back to the
existing shared tmux session constant used elsewhere (instead of
basename(workspaceDir)). Edit the assignment to sessionName (the line using
options.name ?? ...) to use that shared session constant as the default,
removing the sanitizeWindowName(basename(workspaceDir)) fallback to restore the
single shared session behavior.

Comment on lines +339 to +347
} else if (process.env.TMUX) {
// Already inside tmux — launch Claude Code in the CURRENT pane
const suffix = Date.now().toString(36).slice(-4);
const currentWindowName = `${windowName}-${suffix}`;
await tmux.executeTmux(`rename-window ${shellQuote(currentWindowName)}`);
await ensureNativeTeamForLeader(currentWindowName, workspaceDir);
const agentName = basename(workspaceDir);
const resumeSessionId = findLastSessionId(sanitizeTeamName(currentWindowName), agentName, workspaceDir);
const cmd = buildClaudeCommand(currentWindowName, systemPromptFile || undefined, resumeSessionId || undefined);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Inside-tmux flow can target the wrong window and fragments team identity.

rename-window here acts on the current client window (not explicitly bound to sessionName), and the timestamp suffix creates a new team/window identity every run, which breaks deterministic resume/team continuity. This path also skips the GENIE_CWD window env and registry registration used by other startup paths.

Proposed fix
   } else if (process.env.TMUX) {
-      // Already inside tmux — launch Claude Code in the CURRENT pane
-      const suffix = Date.now().toString(36).slice(-4);
-      const currentWindowName = `${windowName}-${suffix}`;
-      await tmux.executeTmux(`rename-window ${shellQuote(currentWindowName)}`);
+      // Already inside tmux
+      const currentSession = (await tmux.executeTmux("display-message -p '#S'")).trim();
+      if (currentSession !== sessionName) {
+        await focusTeamWindow(sessionName, windowName, workspaceDir, systemPromptFile);
+        attachToWindow(sessionName, windowName);
+        return;
+      }
+      const currentWindowName = windowName;
+      await tmux.executeTmux(`rename-window ${shellQuote(currentWindowName)}`);
+      await tmux.setWindowEnv(`${sessionName}:${currentWindowName}`, 'GENIE_CWD', workspaceDir);
       await ensureNativeTeamForLeader(currentWindowName, workspaceDir);
       const agentName = basename(workspaceDir);
       const resumeSessionId = findLastSessionId(sanitizeTeamName(currentWindowName), agentName, workspaceDir);
+      await registerSessionInRegistry(sessionName, currentWindowName, workspaceDir);
       const cmd = buildClaudeCommand(currentWindowName, systemPromptFile || undefined, resumeSessionId || undefined);

Based on learnings: deriveWindowName is the single entry point for window name resolution and should remain the authoritative naming path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/genie-commands/session.ts` around lines 339 - 347, The inside-tmux branch
must use the canonical deriveWindowName and same registration/env setup as other
flows instead of renaming the current client window with a timestamp suffix;
replace the suffix/currentWindowName logic with a call to
deriveWindowName(sessionName?) to produce the authoritative windowName, remove
the ad-hoc Date.now suffix, call ensureNativeTeamForLeader(derivedWindowName,
workspaceDir) and compute resumeSessionId via
findLastSessionId(sanitizeTeamName(derivedWindowName), agentName, workspaceDir),
and ensure the GENIE_CWD window env and registry registration steps used by
other startup paths are executed before building the command
(buildClaudeCommand) so the inside-tmux path remains deterministic and resumes
the correct team/session.

Comment on lines +348 to +349
const { execSync: execSyncCmd } = require('node:child_process');
execSyncCmd(cmd, { stdio: 'inherit', cwd: workspaceDir });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "package.json module type:"
jq -r '.type // "undefined"' package.json

echo
echo "tsconfig module settings:"
fd -a '^tsconfig.*\.json$' | while read -r f; do
  echo "--- $f"
  jq -r '.compilerOptions.module // "undefined"' "$f" 2>/dev/null || true
done

echo
echo "dynamic require() usages under src/genie-commands:"
rg -nP --type=ts -C2 '\brequire\s*\(' src/genie-commands

Repository: automagik-dev/genie

Length of output: 1151


🏁 Script executed:

head -50 src/genie-commands/session.ts | cat -n

Repository: automagik-dev/genie

Length of output: 2020


🏁 Script executed:

rg -nA5 -B5 "^import.*from.*node:child_process" src/genie-commands/session.ts

Repository: automagik-dev/genie

Length of output: 637


🏁 Script executed:

sed -n '345,352p' src/genie-commands/session.ts | cat -n

Repository: automagik-dev/genie

Length of output: 657


Use static import for execSync instead of runtime require().

In ESM mode ("type": "module"), dynamic require() at runtime (line 348) is unreliable and can fail. Add execSync to the existing import from node:child_process at line 14 and call it directly.

Proposed fix
-import { spawnSync } from 'node:child_process';
+import { execSync, spawnSync } from 'node:child_process';

Then at line 348–349:

-      const { execSync: execSyncCmd } = require('node:child_process');
-      execSyncCmd(cmd, { stdio: 'inherit', cwd: workspaceDir });
+      execSync(cmd, { stdio: 'inherit', cwd: workspaceDir });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { execSync: execSyncCmd } = require('node:child_process');
execSyncCmd(cmd, { stdio: 'inherit', cwd: workspaceDir });
execSync(cmd, { stdio: 'inherit', cwd: workspaceDir });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/genie-commands/session.ts` around lines 348 - 349, The code uses a
runtime require to get execSync which fails in ESM; instead add a static import
for execSync from 'node:child_process' alongside the existing imports at the top
of the file, remove the require(...) at the call site, and call execSync(cmd, {
stdio: 'inherit', cwd: workspaceDir }) directly where execSyncCmd is currently
used (referencing execSync, cmd, and workspaceDir to find the call).

Genie added 4 commits March 17, 2026 23:52
Without this flag, CC routes permission requests to a nonexistent
team leader instead of self-approving. The agentType in native team
config wasn't enough — CC needs the CLI flag directly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/team-lead-command.ts (1)

44-54: ⚠️ Potential issue | 🔴 Critical

Fix the identity mismatch: change GENIE_AGENT_NAME to 'team-lead' and update the corresponding test.

Line 49 sets GENIE_AGENT_NAME to the folder name, but lines 51–54 identify this process as team-lead (via --agent-id, --agent-name, and --agent-type). The env var must match the CLI flags for Claude Code native team recognition to work.

The test at src/genie-commands/__tests__/session.test.ts:31-34 explicitly expects GENIE_AGENT_NAME to equal the folder name. This test asserts the buggy behavior and will break after the fix — it must be updated to expect 'team-lead'.

Also, the comment at line 36 ("The agent name is derived from basename(cwd) to match the folder name") contradicts the actual requirement; it should be removed or corrected.

🔧 Proposed changes

In src/lib/team-lead-command.ts:

   const folderName = basename(process.cwd());
   const parts = [
@@
-    `GENIE_AGENT_NAME=${shellQuote(folderName)}`,
+    `GENIE_AGENT_NAME=${shellQuote('team-lead')}`,

Remove or correct the misleading comment at line 36.

In src/genie-commands/__tests__/session.test.ts:

   test('sets GENIE_AGENT_NAME env var to folder name', () => {
     const cmd = buildClaudeCommand('genie');
-    expect(cmd).toContain(`GENIE_AGENT_NAME='${folderName}'`);
+    expect(cmd).toContain(`GENIE_AGENT_NAME='team-lead'`);
   });

Consider renaming the test to reflect the actual purpose.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/team-lead-command.ts` around lines 44 - 54, Change the environment
var GENIE_AGENT_NAME to the literal 'team-lead' so it matches the CLI flags
(--agent-name team-lead / --agent-type team-lead / --agent-id team-lead@...)
instead of using folderName; update the parts array initialization (where
folderName, shellQuote, qTeam are used) to set `GENIE_AGENT_NAME='team-lead'`,
remove or correct the misleading comment about deriving the name from
basename(cwd) in team-lead-command.ts, and update the test in
src/genie-commands/__tests__/session.test.ts (which currently expects
folderName) to assert 'team-lead' (and optionally rename the test to reflect the
new expectation).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/lib/team-lead-command.ts`:
- Around line 44-54: Change the environment var GENIE_AGENT_NAME to the literal
'team-lead' so it matches the CLI flags (--agent-name team-lead / --agent-type
team-lead / --agent-id team-lead@...) instead of using folderName; update the
parts array initialization (where folderName, shellQuote, qTeam are used) to set
`GENIE_AGENT_NAME='team-lead'`, remove or correct the misleading comment about
deriving the name from basename(cwd) in team-lead-command.ts, and update the
test in src/genie-commands/__tests__/session.test.ts (which currently expects
folderName) to assert 'team-lead' (and optionally rename the test to reflect the
new expectation).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c675fb6b-dcf3-43ff-97d0-181fefe55ad5

📥 Commits

Reviewing files that changed from the base of the PR and between 925dc5b and 46d30d4.

📒 Files selected for processing (5)
  • scripts/tmux/genie.tmux.conf
  • src/genie-commands/__tests__/session.test.ts
  • src/lib/provider-adapters.ts
  • src/lib/team-lead-command.ts
  • src/term-commands/agents.ts

* fix(team): replace git worktree with git clone --shared

git worktree shares .git metadata with the parent repo. CC workers
running git operations inside the worktree can flip core.bare=true
on the parent, silently corrupting it.

git clone --shared reuses the same object store (fast, no disk
duplication) but gets its own .git directory, eliminating the
core.bare corruption vector entirely.

Changes:
- ensureWorktree(): create branch in parent then git clone --shared
- disbandTeam(): rm -rf the clone dir instead of git worktree remove
- pruneStaleWorktrees(): remove git worktree prune and core.bare fix
- genie.ts: keep startup guard as legacy safety net with updated comment
- Update tests to use git clone --shared instead of git worktree

* fix(team): inherit git user config in shared clones

git clone --shared creates a separate .git, so local user config
from the parent repo doesn't carry over. CI runners without global
git config would fail on commits inside the clone.

Copy user.name and user.email from parent repo after cloning.

---------

Co-authored-by: Genie <genie@automagik.ai>
@namastex888

Copy link
Copy Markdown
Contributor Author

Emergency: P0 core.bare fix included

This rolling promotion now includes the emergency fix for the core.bare corruption bug (#634, PR #655).

What changed: Replaced all git worktree usage with git clone --shared — prevents CC workers from corrupting the parent repo by flipping core.bare=true.

Risk: Low — net code deletion, 752/752 tests pass, CI green.

Request: Please merge this to main ASAP for emergency release.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/tmux/genie.tmux.conf`:
- Line 59: The tmux status-left command currently pipes genie --version into
head which masks the failure and prevents the "|| echo Genie" fallback from
running; update the status-left line (the shell command inside the #( ... ) used
for status-left) to remove the `| head -1` so the pipeline returns the genie
process exit code and the fallback `|| echo Genie` will execute when `genie
--version` fails. Ensure the remainder of the status-left formatting (the
surrounding #[...] tokens and colors) is left unchanged.

In `@src/lib/team-manager.ts`:
- Around line 176-185: The current branch-creation block in team-manager.ts
silently falls back to creating the new branch from HEAD when the provided
baseBranch can't be resolved (see variables branchExists, branchName,
baseBranch), which can create a branch from the wrong commit; change the logic
so that if both attempts to create from origin/${baseBranch} and ${baseBranch}
fail you surface an explicit error instead of falling back to `git branch
${branchName}` — e.g., capture the caught error(s) and throw or return a clear
error describing that baseBranch could not be found (include baseBranch and
repoPath in the message) so callers can handle it rather than silently creating
the branch from the current HEAD.
- Around line 167-168: The early return that skips cloning when
existsSync(worktreePath) is true is unsafe; instead, validate that worktreePath
points to a healthy git worktree (e.g., check for a .git directory or run a git
probe such as `git rev-parse --is-inside-work-tree`) and only return if that
validation passes; if validation fails, either clean up the stale path (remove
or rename) or surface an error so the subsequent team creation logic uses a
valid worktree; update the check around existsSync(worktreePath) to call a
helper like isValidWorktree(worktreePath) and branch accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9528bb65-1e5b-4cdf-b85d-34937725c22d

📥 Commits

Reviewing files that changed from the base of the PR and between 46d30d4 and 3f6fa34.

📒 Files selected for processing (5)
  • scripts/tmux/genie.tmux.conf
  • src/genie.ts
  • src/lib/team-manager.test.ts
  • src/lib/team-manager.ts
  • src/term-commands/ship.test.ts

Comment thread scripts/tmux/genie.tmux.conf Outdated
set -g status-left "#[bg=#7b2ff7,fg=#e0e0e0,bold] #(genie --version 2>/dev/null | head -1 || echo 'Genie') #[bg=#1a1a2e,fg=#7b2ff7]"
# Left: branding
set -g status-left-length 40
set -g status-left "#[bg=#7b2ff7,fg=#e0e0e0,bold] 🧞 #(genie --version 2>/dev/null | head -1 || echo Genie) #[bg=#1a1a2e,fg=#7b2ff7]"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify current behavior: fallback is masked by pipeline status.
current="$(bash -lc 'missing_genie --version 2>/dev/null | head -1 || echo Genie')"
printf "current=[%s]\n" "$current"

# Verify fixed behavior: fallback appears when command is missing.
fixed="$(bash -lc 'missing_genie --version 2>/dev/null || echo Genie')"
printf "fixed=[%s]\n" "$fixed"

Repository: automagik-dev/genie

Length of output: 302


Remove | head -1 to ensure fallback logic executes when genie is missing.

On line 59, the head command masks pipeline failure. When genie --version fails, head still exits successfully (exit 0), preventing the || echo Genie fallback from triggering. The result is blank status output instead of the "Genie" fallback.

Proposed fix
-set -g status-left "#[bg=#7b2ff7,fg=#e0e0e0,bold] 🧞 #(genie --version 2>/dev/null | head -1 || echo Genie) #[bg=#1a1a2e,fg=#7b2ff7]"
+set -g status-left "#[bg=#7b2ff7,fg=#e0e0e0,bold] 🧞 #(genie --version 2>/dev/null || echo Genie) #[bg=#1a1a2e,fg=#7b2ff7]"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
set -g status-left "#[bg=#7b2ff7,fg=#e0e0e0,bold] 🧞 #(genie --version 2>/dev/null | head -1 || echo Genie) #[bg=#1a1a2e,fg=#7b2ff7]"
set -g status-left "#[bg=#7b2ff7,fg=#e0e0e0,bold] 🧞 #(genie --version 2>/dev/null || echo Genie) #[bg=#1a1a2e,fg=#7b2ff7]"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/tmux/genie.tmux.conf` at line 59, The tmux status-left command
currently pipes genie --version into head which masks the failure and prevents
the "|| echo Genie" fallback from running; update the status-left line (the
shell command inside the #( ... ) used for status-left) to remove the `| head
-1` so the pipeline returns the genie process exit code and the fallback `||
echo Genie` will execute when `genie --version` fails. Ensure the remainder of
the status-left formatting (the surrounding #[...] tokens and colors) is left
unchanged.

Comment thread src/lib/team-manager.ts
Comment on lines +167 to 168
// Skip if clone already exists on disk
if (existsSync(worktreePath)) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate existing target path before returning.

Line 167 returns on path existence alone. If that directory is stale/partial/non-git, team creation proceeds with an invalid worktreePath.

Proposed fix
-  // Skip if clone already exists on disk
-  if (existsSync(worktreePath)) return;
+  // Skip only if a valid git clone already exists on disk
+  if (existsSync(worktreePath)) {
+    try {
+      await $`git -C ${worktreePath} rev-parse --is-inside-work-tree`.quiet();
+      return;
+    } catch {
+      throw new Error(`Path exists but is not a valid git clone: ${worktreePath}`);
+    }
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/team-manager.ts` around lines 167 - 168, The early return that skips
cloning when existsSync(worktreePath) is true is unsafe; instead, validate that
worktreePath points to a healthy git worktree (e.g., check for a .git directory
or run a git probe such as `git rev-parse --is-inside-work-tree`) and only
return if that validation passes; if validation fails, either clean up the stale
path (remove or rename) or surface an error so the subsequent team creation
logic uses a valid worktree; update the check around existsSync(worktreePath) to
call a helper like isValidWorktree(worktreePath) and branch accordingly.

Comment thread src/lib/team-manager.ts
Comment on lines +176 to +185
// Branch doesn't exist yet — create it from baseBranch
if (!branchExists) {
try {
await $`git -C ${repoPath} branch ${branchName} origin/${baseBranch}`.quiet();
} catch {
try {
await $`git -C ${repoPath} branch ${branchName} ${baseBranch}`.quiet();
} catch {
await $`git -C ${repoPath} branch ${branchName}`.quiet();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not silently ignore missing baseBranch.

Line 184 falls back to git branch ${branchName} (current HEAD) when baseBranch cannot be resolved. That can create the team branch from the wrong commit without surfacing an error.

Proposed fix
         try {
           await $`git -C ${repoPath} branch ${branchName} ${baseBranch}`.quiet();
         } catch {
-          await $`git -C ${repoPath} branch ${branchName}`.quiet();
+          throw new Error(
+            `Base branch "${baseBranch}" was not found locally or on origin in ${repoPath}`,
+          );
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/team-manager.ts` around lines 176 - 185, The current branch-creation
block in team-manager.ts silently falls back to creating the new branch from
HEAD when the provided baseBranch can't be resolved (see variables branchExists,
branchName, baseBranch), which can create a branch from the wrong commit; change
the logic so that if both attempts to create from origin/${baseBranch} and
${baseBranch} fail you surface an explicit error instead of falling back to `git
branch ${branchName}` — e.g., capture the caught error(s) and throw or return a
clear error describing that baseBranch could not be found (include baseBranch
and repoPath in the message) so callers can handle it rather than silently
creating the branch from the current HEAD.

…-border (#656)

- Top: pane-border with system info (git, CPU, RAM, clock)
- Bottom line 0: native clickable window tabs
- Bottom line 1: clickable session list + Genie version (right)
- Fix update-check to use @automagik/genie (scoped package)
- Only show update notice when npm version is actually newer

Co-authored-by: Genie <genie@automagik.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant