Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Thumbs.db

# AI tooling
.gemini/
.gemini_security/
.claude/
.superpowers/
docs/superpowers/
Expand Down
241 changes: 241 additions & 0 deletions QWEN.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions claude/src/hooks/logic/before-agent-logic.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const { log } = require('../../core/logger');
const { detectAgentFromPrompt } = require('../../core/agent-registry');
const { detectAgentFromPrompt, normalizeAgentName } = require('../../core/agent-registry');
const { assertSessionId } = require('../../lib/validation');
const { readFileSafe } = require('../../lib/io');
const hookState = require('./hook-state');
Expand All @@ -23,7 +23,7 @@ const state = require('../../state/session-state');
function handleBeforeAgent(ctx) {
hookState.pruneStale();

const agentName = detectAgentFromPrompt(ctx.agentInput);
const agentName = detectAgentFromPrompt(ctx.agentInput) || normalizeAgentName(ctx.agentName);

let validSession = false;
try { assertSessionId(ctx.sessionId); validSession = true; } catch (_) {}
Expand Down
83 changes: 83 additions & 0 deletions claude/src/platforms/shared/adapters/qwen-adapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict';

const { readBoundedJson } = require('../../../core/stdin-reader');

/**
* Qwen Code hook I/O adapter.
* Normalizes Qwen Code stdin JSON to the internal context contract
* and formats internal responses for Qwen Code stdout.
*
* Each hook event has a distinct payload in Qwen. This adapter
* normalizes to an internal contract and serializes per-event output.
*
* Event reference:
* - SessionStart: session bootstrap (common + permission_mode, source, model)
* - SessionEnd: session teardown (common + reason)
* - SubagentStart: subagent lifecycle start (common + agent_id, agent_type, permission_mode)
* - SubagentStop: subagent lifecycle end (common + agent_id, agent_type, stop_hook_active, last_assistant_message)
* - PreToolUse: permission-oriented (uses permissionDecision output, not handled here)
*
* Internal contract fields:
* event, sessionId, cwd, transcriptPath, permissionMode,
* agentId, agentName, agentInput, agentResult, source, model, reason, stopHookActive
*
* Output contract (for non-permission hooks):
* { continue, decision, reason?, hookSpecificOutput?: { additionalContext } }
*/

function normalizeInput(raw) {
const event = raw.hook_event_name || '';

return {
event,
sessionId: raw.session_id || '',
cwd: raw.cwd || '',
transcriptPath: raw.transcript_path || '',
permissionMode: raw.permission_mode || '',
agentId: raw.agent_id || '',
agentName: raw.agent_type || null,
agentInput: null,
agentResult: event === 'SubagentStop'
? (raw.last_assistant_message || '')
: null,
source: raw.source || '',
model: raw.model || '',
reason: raw.reason || '',
stopHookActive: raw.stop_hook_active === true || raw.stop_hook_active === 'true',
};
}

/**
* Serialize internal result to Qwen-native output.
*
* Result from logic: { action: 'allow'|'deny', message: string|null, reason: string|null }
*
* For SessionStart, SubagentStart, SubagentStop, SessionEnd:
* standard output + optional hookSpecificOutput.additionalContext
*/
function formatOutput(result) {
const isDeny = result.action === 'deny';
const out = {};

// Only emit decision/reason when explicitly controlling flow
if (isDeny) {
out.continue = false;
out.decision = 'block';
out.reason = result.reason || 'Blocked by hook';
} else if (result.reason) {
out.decision = 'allow';
out.reason = result.reason;
}

if (result.message) {
out.hookSpecificOutput = { additionalContext: result.message };
}

return out;
}

function errorFallback() {
return { continue: true, decision: 'allow' };
}

module.exports = { normalizeInput, formatOutput, errorFallback, readBoundedStdin: readBoundedJson };
3 changes: 3 additions & 0 deletions claude/src/platforms/shared/hook-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ adapter.readBoundedStdin()
})
.then((result) => {
process.stdout.write(JSON.stringify(adapter.formatOutput(result)) + '\n');
if (result.action === 'deny') {
process.exitCode = 2;
}
})
.catch((err) => {
process.stderr.write('Hook error: ' + err.message + '\n');
Expand Down
2 changes: 2 additions & 0 deletions hooks/adapters/qwen-adapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
'use strict';
module.exports = require('../../src/platforms/shared/adapters/qwen-adapter');
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
"docs/",
"GEMINI.md",
"gemini-extension.json",
"QWEN.md",
"qwen-extension.json",
"qwen/",
"CHANGELOG.md"
]
}
4 changes: 2 additions & 2 deletions plugins/maestro/src/hooks/logic/before-agent-logic.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const { log } = require('../../core/logger');
const { detectAgentFromPrompt } = require('../../core/agent-registry');
const { detectAgentFromPrompt, normalizeAgentName } = require('../../core/agent-registry');
const { assertSessionId } = require('../../lib/validation');
const { readFileSafe } = require('../../lib/io');
const hookState = require('./hook-state');
Expand All @@ -23,7 +23,7 @@ const state = require('../../state/session-state');
function handleBeforeAgent(ctx) {
hookState.pruneStale();

const agentName = detectAgentFromPrompt(ctx.agentInput);
const agentName = detectAgentFromPrompt(ctx.agentInput) || normalizeAgentName(ctx.agentName);

let validSession = false;
try { assertSessionId(ctx.sessionId); validSession = true; } catch (_) {}
Expand Down
83 changes: 83 additions & 0 deletions plugins/maestro/src/platforms/shared/adapters/qwen-adapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict';

const { readBoundedJson } = require('../../../core/stdin-reader');

/**
* Qwen Code hook I/O adapter.
* Normalizes Qwen Code stdin JSON to the internal context contract
* and formats internal responses for Qwen Code stdout.
*
* Each hook event has a distinct payload in Qwen. This adapter
* normalizes to an internal contract and serializes per-event output.
*
* Event reference:
* - SessionStart: session bootstrap (common + permission_mode, source, model)
* - SessionEnd: session teardown (common + reason)
* - SubagentStart: subagent lifecycle start (common + agent_id, agent_type, permission_mode)
* - SubagentStop: subagent lifecycle end (common + agent_id, agent_type, stop_hook_active, last_assistant_message)
* - PreToolUse: permission-oriented (uses permissionDecision output, not handled here)
*
* Internal contract fields:
* event, sessionId, cwd, transcriptPath, permissionMode,
* agentId, agentName, agentInput, agentResult, source, model, reason, stopHookActive
*
* Output contract (for non-permission hooks):
* { continue, decision, reason?, hookSpecificOutput?: { additionalContext } }
*/

function normalizeInput(raw) {
const event = raw.hook_event_name || '';

return {
event,
sessionId: raw.session_id || '',
cwd: raw.cwd || '',
transcriptPath: raw.transcript_path || '',
permissionMode: raw.permission_mode || '',
agentId: raw.agent_id || '',
agentName: raw.agent_type || null,
agentInput: null,
agentResult: event === 'SubagentStop'
? (raw.last_assistant_message || '')
: null,
source: raw.source || '',
model: raw.model || '',
reason: raw.reason || '',
stopHookActive: raw.stop_hook_active === true || raw.stop_hook_active === 'true',
};
}

/**
* Serialize internal result to Qwen-native output.
*
* Result from logic: { action: 'allow'|'deny', message: string|null, reason: string|null }
*
* For SessionStart, SubagentStart, SubagentStop, SessionEnd:
* standard output + optional hookSpecificOutput.additionalContext
*/
function formatOutput(result) {
const isDeny = result.action === 'deny';
const out = {};

// Only emit decision/reason when explicitly controlling flow
if (isDeny) {
out.continue = false;
out.decision = 'block';
out.reason = result.reason || 'Blocked by hook';
} else if (result.reason) {
out.decision = 'allow';
out.reason = result.reason;
}

if (result.message) {
out.hookSpecificOutput = { additionalContext: result.message };
}

return out;
}

function errorFallback() {
return { continue: true, decision: 'allow' };
}

module.exports = { normalizeInput, formatOutput, errorFallback, readBoundedStdin: readBoundedJson };
3 changes: 3 additions & 0 deletions plugins/maestro/src/platforms/shared/hook-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ adapter.readBoundedStdin()
})
.then((result) => {
process.stdout.write(JSON.stringify(adapter.formatOutput(result)) + '\n');
if (result.action === 'deny') {
process.exitCode = 2;
}
})
.catch((err) => {
process.stderr.write('Hook error: ' + err.message + '\n');
Expand Down
55 changes: 55 additions & 0 deletions qwen-extension.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "maestro",
"version": "1.6.1",
"description": "Multi-agent development orchestration platform — 22 specialists, 4-phase orchestration, native parallel subagents, persistent sessions, and standalone review/debug/security/perf/seo/a11y/compliance commands",
"contextFileName": "QWEN.md",
"settings": [
{
"name": "Disabled Agents",
"description": "Comma-separated list of agent names to exclude from implementation planning.",
"envVar": "MAESTRO_DISABLED_AGENTS"
},
{
"name": "Max Retries",
"description": "Maximum retry attempts per phase before escalating to user.",
"envVar": "MAESTRO_MAX_RETRIES"
},
{
"name": "Auto Archive",
"description": "Automatically archive session state on successful completion (true/false).",
"envVar": "MAESTRO_AUTO_ARCHIVE"
},
{
"name": "Validation",
"description": "Post-phase validation strictness level (strict/normal/lenient).",
"envVar": "MAESTRO_VALIDATION_STRICTNESS"
},
{
"name": "State Directory",
"description": "Base directory for session state and plans (default: docs/maestro).",
"envVar": "MAESTRO_STATE_DIR"
},
{
"name": "Max Concurrent",
"description": "Maximum subagents emitted in one native parallel batch turn (0 = dispatch the entire ready batch).",
"envVar": "MAESTRO_MAX_CONCURRENT"
},
{
"name": "Execution Mode",
"description": "Phase 3 execution mode: 'parallel' (native concurrent subagents), 'sequential' (one at a time), or 'ask' (prompt each time). Default: ask.",
"envVar": "MAESTRO_EXECUTION_MODE"
}
],
"mcpServers": {
"maestro": {
"command": "node",
"args": [
"${extensionPath}/mcp/maestro-server.js"
],
"cwd": "${extensionPath}",
"env": {
"MAESTRO_WORKSPACE_PATH": "${workspacePath}"
}
}
}
}
18 changes: 18 additions & 0 deletions qwen/agents/accessibility_specialist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: accessibility_specialist
kind: local
description: "Accessibility specialist for WCAG compliance auditing, ARIA implementation review, keyboard navigation testing, and inclusive design assessment. Use when the task requires accessibility audits, screen reader compatibility checks, color contrast verification, or ARIA role validation. For example: auditing a web app for WCAG 2.1 AA compliance, reviewing keyboard navigation in modal dialogs, or validating ARIA usage in custom components."
max_turns: 20
tools:
- read_file
- list_directory
- glob
- grep_search
- run_shell_command
- web_search
- todo_write
- read_many_files
- ask_user_question
---

Agent methodology loaded via MCP tool `get_agent`. Call `get_agent(agents: ["accessibility-specialist"])` to read the full methodology at delegation time.
20 changes: 20 additions & 0 deletions qwen/agents/analytics_engineer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
name: analytics_engineer
kind: local
description: "Analytics engineering specialist for event tracking implementation, analytics schemas, conversion funnels, A/B test design, and measurement planning. Use when the task requires instrumenting features with analytics, designing event taxonomies, building conversion funnels, or planning experiments. For example: adding event tracking to a checkout flow, designing an A/B test for a pricing page, or defining KPI dashboards."
max_turns: 25
tools:
- read_file
- list_directory
- glob
- grep_search
- write_file
- edit
- run_shell_command
- web_search
- todo_write
- read_many_files
- ask_user_question
---

Agent methodology loaded via MCP tool `get_agent`. Call `get_agent(agents: ["analytics-engineer"])` to read the full methodology at delegation time.
17 changes: 17 additions & 0 deletions qwen/agents/api_designer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: api_designer
kind: local
description: "API design specialist for endpoint design, request/response contracts, and API versioning strategies. Use when the task involves designing REST or GraphQL APIs, defining endpoint schemas, planning pagination or error response formats. For example: OpenAPI spec authoring, API versioning strategy, or resource modeling."
max_turns: 15
tools:
- read_file
- list_directory
- glob
- grep_search
- read_many_files
- ask_user_question
- web_search
- web_fetch
---

Agent methodology loaded via MCP tool `get_agent`. Call `get_agent(agents: ["api-designer"])` to read the full methodology at delegation time.
17 changes: 17 additions & 0 deletions qwen/agents/architect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
name: architect
kind: local
description: "System design specialist for architecture decisions, technology selection, and high-level component design. Use when the task requires evaluating architectural trade-offs, designing system components, selecting technology stacks, or planning service boundaries. For example: microservice decomposition, database schema design, or API contract planning."
max_turns: 15
tools:
- read_file
- list_directory
- glob
- grep_search
- web_search
- read_many_files
- ask_user_question
- web_fetch
---

Agent methodology loaded via MCP tool `get_agent`. Call `get_agent(agents: ["architect"])` to read the full methodology at delegation time.
15 changes: 15 additions & 0 deletions qwen/agents/code_reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
name: code_reviewer
kind: local
description: "Code review specialist for identifying bugs, security vulnerabilities, and code quality issues. Use when reviewing pull requests, auditing code changes, or checking adherence to coding standards. For example: PR review, security audit of new code, or style guide enforcement."
max_turns: 15
tools:
- read_file
- list_directory
- glob
- grep_search
- read_many_files
- ask_user_question
---

Agent methodology loaded via MCP tool `get_agent`. Call `get_agent(agents: ["code-reviewer"])` to read the full methodology at delegation time.
Loading
Loading