From 60cee553a24ea2de2ff6ae0a91cf9de2788cea68 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 17 Mar 2026 04:09:13 +0000 Subject: [PATCH 1/4] chore(version): bump to 3.260317.3 [skip ci] --- .claude-plugin/marketplace.json | 2 +- openclaw.plugin.json | 2 +- package.json | 2 +- plugins/genie/.claude-plugin/plugin.json | 2 +- plugins/genie/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4b99a125d..2c38727e6 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "genie", - "version": "3.260317.2", + "version": "3.260317.3", "source": "./plugins/genie", "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, wish them into plans, make with parallel agents, ship as one team. A coding genie that grows with your project." } diff --git a/openclaw.plugin.json b/openclaw.plugin.json index 5b348322e..3fe11d00f 100644 --- a/openclaw.plugin.json +++ b/openclaw.plugin.json @@ -2,7 +2,7 @@ "id": "genie", "name": "Genie", "description": "Skills, agents, and hooks for the Genie CLI terminal orchestration toolkit", - "version": "3.260317.2", + "version": "3.260317.3", "configSchema": { "type": "object", "additionalProperties": false, diff --git a/package.json b/package.json index 9d16347c0..88a28f2a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@automagik/genie", - "version": "3.260317.2", + "version": "3.260317.3", "description": "Collaborative terminal toolkit for human + AI workflows", "type": "module", "bin": { diff --git a/plugins/genie/.claude-plugin/plugin.json b/plugins/genie/.claude-plugin/plugin.json index 404d5d47b..a7c231f10 100644 --- a/plugins/genie/.claude-plugin/plugin.json +++ b/plugins/genie/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "genie", - "version": "3.260317.2", + "version": "3.260317.3", "description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.", "author": { "name": "Namastex Labs" diff --git a/plugins/genie/package.json b/plugins/genie/package.json index 667c84060..9bf87c5c6 100644 --- a/plugins/genie/package.json +++ b/plugins/genie/package.json @@ -1,6 +1,6 @@ { "name": "genie-plugin", - "version": "3.260317.2", + "version": "3.260317.3", "private": true, "description": "Runtime dependencies for genie bundled CLIs", "type": "module", From b6c687017a787b50e8587f66a935c9c85ec3f4ea Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 17 Mar 2026 01:16:13 -0300 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20team-lead=20prompt=20=E2=80=94=20ski?= =?UTF-8?q?p=20status=20check=20before=20first=20dispatch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit genie work auto-initializes state, so checking genie status before the first dispatch is a wasted step that errors. Added explicit instruction: "do NOT run genie status before your first dispatch." --- plugins/genie/agents/team-lead.md | 10 +++++----- plugins/genie/agents/team-lead/AGENTS.md | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/genie/agents/team-lead.md b/plugins/genie/agents/team-lead.md index 3e69dc0f5..4b23b620e 100644 --- a/plugins/genie/agents/team-lead.md +++ b/plugins/genie/agents/team-lead.md @@ -44,18 +44,18 @@ For cross-session agents, use `genie send '' --to ` via Bash. ## Phase 1 — Read Wish -Read the WISH.md at the path provided in your initial prompt. Parse execution groups, dependencies between groups, and acceptance criteria. Understand the full scope before dispatching anything. +Read the WISH.md at the path provided in your initial prompt. Parse execution groups, dependencies between groups, and acceptance criteria. -**Gate:** All groups parsed, dependency DAG verified (no circular deps), acceptance criteria extracted. If wish is unparseable or missing groups, report to PM and stop. +**Gate:** All groups parsed, dependency DAG understood. If wish is unparseable or missing groups, report to PM and stop. ## Phase 2 — Execute Groups -Dispatch groups whose dependencies are satisfied. Run independent groups in parallel. Never start a group before its dependencies complete. +Dispatch groups whose dependencies are satisfied. `genie work` auto-initializes state on first call — do NOT run `genie status` before your first dispatch. Just dispatch immediately. ```bash -genie work engineer # # Dispatches and spawns engineer +genie work engineer # # Auto-inits state, sets in_progress, spawns engineer genie read -engineer # Monitor progress genie done # # Mark group complete -genie status # Check overall progress +genie status # Check progress (only AFTER first dispatch) ``` One group per engineer dispatch. Wait for completion before marking done. diff --git a/plugins/genie/agents/team-lead/AGENTS.md b/plugins/genie/agents/team-lead/AGENTS.md index 3e69dc0f5..4b23b620e 100644 --- a/plugins/genie/agents/team-lead/AGENTS.md +++ b/plugins/genie/agents/team-lead/AGENTS.md @@ -44,18 +44,18 @@ For cross-session agents, use `genie send '' --to ` via Bash. ## Phase 1 — Read Wish -Read the WISH.md at the path provided in your initial prompt. Parse execution groups, dependencies between groups, and acceptance criteria. Understand the full scope before dispatching anything. +Read the WISH.md at the path provided in your initial prompt. Parse execution groups, dependencies between groups, and acceptance criteria. -**Gate:** All groups parsed, dependency DAG verified (no circular deps), acceptance criteria extracted. If wish is unparseable or missing groups, report to PM and stop. +**Gate:** All groups parsed, dependency DAG understood. If wish is unparseable or missing groups, report to PM and stop. ## Phase 2 — Execute Groups -Dispatch groups whose dependencies are satisfied. Run independent groups in parallel. Never start a group before its dependencies complete. +Dispatch groups whose dependencies are satisfied. `genie work` auto-initializes state on first call — do NOT run `genie status` before your first dispatch. Just dispatch immediately. ```bash -genie work engineer # # Dispatches and spawns engineer +genie work engineer # # Auto-inits state, sets in_progress, spawns engineer genie read -engineer # Monitor progress genie done # # Mark group complete -genie status # Check overall progress +genie status # Check progress (only AFTER first dispatch) ``` One group per engineer dispatch. Wait for completion before marking done. From f142f0c956284c1fae76a40dfcaa62d5c986a86f Mon Sep 17 00:00:00 2001 From: Test User Date: Tue, 17 Mar 2026 01:49:32 -0300 Subject: [PATCH 3/4] fix(dispatch): accept lettered group names (A, B) not just numbered (1, 2) parseWishGroups() regex was \d+ (digits only), so wishes with Group A / Group B were parsed as 0 groups. Changed to [A-Za-z0-9]+ to accept both styles. Also fixed the error message group listing. --- src/term-commands/dispatch.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/term-commands/dispatch.ts b/src/term-commands/dispatch.ts index 4c55e94fb..abb03311c 100644 --- a/src/term-commands/dispatch.ts +++ b/src/term-commands/dispatch.ts @@ -140,11 +140,12 @@ function getGitDiff(): string { /** * Parse WISH.md content to extract group definitions for state initialization. - * Looks for `### Group : ` headings and `**depends-on:**` lines. + * Looks for `### Group <id>: <title>` headings and `**depends-on:**` lines. + * Accepts both numbered (Group 1) and lettered (Group A) identifiers. */ export function parseWishGroups(content: string): GroupDefinition[] { const groups: GroupDefinition[] = []; - const groupPattern = /^### Group (\d+):/gim; + const groupPattern = /^### Group ([A-Za-z0-9]+):/gim; let match: RegExpExecArray | null = groupPattern.exec(content); while (match !== null) { @@ -153,7 +154,7 @@ export function parseWishGroups(content: string): GroupDefinition[] { // Find the next group heading or end of content const rest = content.slice(start + match[0].length); - const nextGroupIdx = rest.search(/^### Group \d+:/m); + const nextGroupIdx = rest.search(/^### Group [A-Za-z0-9]+:/m); const section = nextGroupIdx !== -1 ? rest.slice(0, nextGroupIdx) : rest; // Look for **depends-on:** line within this group section @@ -274,7 +275,7 @@ export async function workDispatchCommand(agentName: string, ref: string): Promi if (!groupSection) { console.error(`❌ Group "${group}" not found in ${wishPath}`); console.error(' Available groups:'); - const groups = content.match(/^### Group \d+:.*$/gm); + const groups = content.match(/^### Group [A-Za-z0-9]+:.*$/gm); if (groups) { for (const g of groups) console.error(` ${g}`); } From 8dab7e7d4f1bd3a65064508bb82db2917eab57f0 Mon Sep 17 00:00:00 2001 From: Test User <test@test.com> Date: Tue, 17 Mar 2026 02:42:21 -0300 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20scope=20killWorkersByName=20by=20tea?= =?UTF-8?q?m=20=E2=80=94=20prevents=20killing=20other=20teams'=20workers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit killWorkersByName filtered by role name only (e.g., "engineer"), which is shared across all teams. When one team called genie team done, it killed engineers from ALL teams. Now accepts a teamName parameter and filters by both role AND team. Closes #626 --- src/lib/team-manager.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/lib/team-manager.ts b/src/lib/team-manager.ts index 5b96415c9..a212a4678 100644 --- a/src/lib/team-manager.ts +++ b/src/lib/team-manager.ts @@ -120,10 +120,12 @@ export function validateBranchName(name: string): void { // Agent Kill Helper // ============================================================================ -/** Best-effort kill all running workers matching a given agent name (by role or id). */ -async function killWorkersByName(agentName: string): Promise<void> { +/** Best-effort kill all running workers matching a given agent name, scoped to a team. */ +async function killWorkersByName(agentName: string, teamName?: string): Promise<void> { const workers = await registry.list(); - const matches = workers.filter((w) => w.role === agentName || w.id === agentName); + const matches = workers.filter( + (w) => (w.role === agentName || w.id === agentName) && (!teamName || w.team === teamName), + ); for (const w of matches) { try { if (w.paneId && w.paneId !== 'inline') { @@ -312,10 +314,10 @@ export async function disbandTeam(teamName: string): Promise<boolean> { } } - // Kill all running team members + // Kill all running team members (scoped to this team only) for (const member of config.members) { try { - await killWorkersByName(member); + await killWorkersByName(member, teamName); } catch { // Best-effort — continue with other members } @@ -426,14 +428,14 @@ export async function listMembers(teamName: string): Promise<string[] | null> { return config.members; } -/** Kill all running workers for a team's members. Best-effort — continues on failure. */ +/** Kill all running workers for a team's members. Scoped to the team — won't kill other teams' workers. */ export async function killTeamMembers(teamName: string): Promise<void> { const config = await getTeam(teamName); if (!config) return; for (const member of config.members) { try { - await killWorkersByName(member); + await killWorkersByName(member, teamName); } catch { // Best-effort — continue with other members }