mumucc 0.4.10 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mumucc",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
4
4
|
"description": "Open-source AI coding assistant CLI with multi-model support (Anthropic, OpenAI/GPT, DeepSeek, GLM, Ollama, etc.), MCP integration, agent swarms, and out-of-the-box developer experience.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/shims/globals.ts
CHANGED
|
@@ -294,9 +294,8 @@ export const AgentTool = buildTool({
|
|
|
294
294
|
// Teammates (in-process or tmux) passing `name` would trigger spawnTeammate()
|
|
295
295
|
// below, but TeamFile.members is a flat array with one leadAgentId — nested
|
|
296
296
|
// teammates land in the roster with no provenance and confuse the lead.
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
}, appState);
|
|
297
|
+
const explicitTeamName = team_name;
|
|
298
|
+
const teamName = explicitTeamName;
|
|
300
299
|
if (isTeammate() && teamName && name) {
|
|
301
300
|
throw new Error('Teammates cannot spawn other teammates — the team roster is flat. To spawn a subagent instead, omit the `name` parameter.');
|
|
302
301
|
}
|
|
@@ -309,7 +308,7 @@ export const AgentTool = buildTool({
|
|
|
309
308
|
|
|
310
309
|
// Check if this is a multi-agent spawn request
|
|
311
310
|
// Spawn is triggered when team_name is set (from param or context) and name is provided
|
|
312
|
-
if (
|
|
311
|
+
if (explicitTeamName && name) {
|
|
313
312
|
// Set agent definition color for grouped UI display before spawning
|
|
314
313
|
const agentDef = subagent_type ? toolUseContext.options.agentDefinitions.activeAgents.find(a => a.agentType === subagent_type) : undefined;
|
|
315
314
|
if (agentDef?.color) {
|
|
@@ -340,7 +339,7 @@ export const AgentTool = buildTool({
|
|
|
340
339
|
name,
|
|
341
340
|
prompt,
|
|
342
341
|
description,
|
|
343
|
-
team_name:
|
|
342
|
+
team_name: explicitTeamName,
|
|
344
343
|
use_splitpane: true,
|
|
345
344
|
plan_mode_required: spawnMode === 'plan',
|
|
346
345
|
model: resolvedTeammateModel,
|
|
@@ -407,7 +406,7 @@ export const AgentTool = buildTool({
|
|
|
407
406
|
// Same lifecycle constraint as the run_in_background guard above, but for
|
|
408
407
|
// agent definitions that force background via `background: true`. Checked
|
|
409
408
|
// here because selectedAgent is only now resolved.
|
|
410
|
-
if (isInProcessTeammate() &&
|
|
409
|
+
if (isInProcessTeammate() && explicitTeamName && selectedAgent.background === true) {
|
|
411
410
|
throw new Error(`In-process teammates cannot spawn background agents. Agent '${selectedAgent.agentType}' has background: true in its definition.`);
|
|
412
411
|
}
|
|
413
412
|
|
|
@@ -45,6 +45,34 @@ const inputSchema = lazySchema(() =>
|
|
|
45
45
|
'Type/role of the team lead (e.g., "researcher", "test-runner"). ' +
|
|
46
46
|
'Used for team file and inter-agent coordination.',
|
|
47
47
|
),
|
|
48
|
+
members: z
|
|
49
|
+
.array(
|
|
50
|
+
z.strictObject({
|
|
51
|
+
name: z.string().describe('Unique teammate display name.'),
|
|
52
|
+
agent_type: z
|
|
53
|
+
.string()
|
|
54
|
+
.optional()
|
|
55
|
+
.describe('Agent type/frontmatter role for this member.'),
|
|
56
|
+
model: z
|
|
57
|
+
.string()
|
|
58
|
+
.optional()
|
|
59
|
+
.describe(
|
|
60
|
+
'Explicit model for this member (for example openai:gpt-5.4, kimi:kimi-for-coding, minimax:MiniMax-M2.7-highspeed, or opus).',
|
|
61
|
+
),
|
|
62
|
+
mode: z
|
|
63
|
+
.string()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe('Optional permission mode hint for this member.'),
|
|
66
|
+
prompt: z
|
|
67
|
+
.string()
|
|
68
|
+
.optional()
|
|
69
|
+
.describe('Optional initial task/purpose note for this member.'),
|
|
70
|
+
}),
|
|
71
|
+
)
|
|
72
|
+
.optional()
|
|
73
|
+
.describe(
|
|
74
|
+
'Optional teammate definitions to seed into the team config at creation time.',
|
|
75
|
+
),
|
|
48
76
|
}),
|
|
49
77
|
)
|
|
50
78
|
type InputSchema = ReturnType<typeof inputSchema>
|
|
@@ -53,6 +81,7 @@ export type Output = {
|
|
|
53
81
|
team_name: string
|
|
54
82
|
team_file_path: string
|
|
55
83
|
lead_agent_id: string
|
|
84
|
+
member_count?: number
|
|
56
85
|
}
|
|
57
86
|
|
|
58
87
|
export type Input = z.infer<InputSchema>
|
|
@@ -127,7 +156,7 @@ export const TeamCreateTool: Tool<InputSchema, Output> = buildTool({
|
|
|
127
156
|
|
|
128
157
|
async call(input, context) {
|
|
129
158
|
const { setAppState, getAppState } = context
|
|
130
|
-
const { team_name, description: _description, agent_type } = input
|
|
159
|
+
const { team_name, description: _description, agent_type, members } = input
|
|
131
160
|
|
|
132
161
|
// Check if already in a team - restrict to one team per leader
|
|
133
162
|
const appState = getAppState()
|
|
@@ -174,6 +203,28 @@ export const TeamCreateTool: Tool<InputSchema, Output> = buildTool({
|
|
|
174
203
|
],
|
|
175
204
|
}
|
|
176
205
|
|
|
206
|
+
const seenNames = new Set([TEAM_LEAD_NAME])
|
|
207
|
+
for (const member of members ?? []) {
|
|
208
|
+
const sanitizedMemberName = sanitizeName(member.name)
|
|
209
|
+
if (!member.name.trim()) continue
|
|
210
|
+
if (seenNames.has(member.name)) continue
|
|
211
|
+
seenNames.add(member.name)
|
|
212
|
+
|
|
213
|
+
teamFile.members.push({
|
|
214
|
+
agentId: formatAgentId(member.name, finalTeamName),
|
|
215
|
+
name: member.name,
|
|
216
|
+
agentType: member.agent_type,
|
|
217
|
+
model: member.model,
|
|
218
|
+
prompt: member.prompt,
|
|
219
|
+
joinedAt: Date.now(),
|
|
220
|
+
tmuxPaneId: '',
|
|
221
|
+
cwd: getCwd(),
|
|
222
|
+
subscriptions: [],
|
|
223
|
+
isActive: false,
|
|
224
|
+
...(member.mode ? { mode: member.mode as any } : {}),
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
177
228
|
await writeTeamFileAsync(finalTeamName, teamFile)
|
|
178
229
|
// Track for session-end cleanup — teams were left on disk forever
|
|
179
230
|
// unless explicitly TeamDelete'd (gh-32730).
|
|
@@ -232,6 +283,7 @@ export const TeamCreateTool: Tool<InputSchema, Output> = buildTool({
|
|
|
232
283
|
team_name: finalTeamName,
|
|
233
284
|
team_file_path: teamFilePath,
|
|
234
285
|
lead_agent_id: leadAgentId,
|
|
286
|
+
member_count: teamFile.members.length,
|
|
235
287
|
},
|
|
236
288
|
}
|
|
237
289
|
},
|
|
@@ -26,13 +26,31 @@ Create a new team to coordinate multiple agents working on a project. Teams have
|
|
|
26
26
|
\`\`\`
|
|
27
27
|
{
|
|
28
28
|
"team_name": "my-project",
|
|
29
|
-
"description": "Working on feature X"
|
|
29
|
+
"description": "Working on feature X",
|
|
30
|
+
"members": [
|
|
31
|
+
{
|
|
32
|
+
"name": "backend",
|
|
33
|
+
"agent_type": "backend-architect",
|
|
34
|
+
"model": "openai:gpt-5.4"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "frontend",
|
|
38
|
+
"agent_type": "ui-designer",
|
|
39
|
+
"model": "kimi:kimi-for-coding"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "deploy",
|
|
43
|
+
"agent_type": "deployment-engineer",
|
|
44
|
+
"model": "minimax:MiniMax-M2.7-highspeed"
|
|
45
|
+
}
|
|
46
|
+
]
|
|
30
47
|
}
|
|
31
48
|
\`\`\`
|
|
32
49
|
|
|
33
50
|
This creates:
|
|
34
51
|
- A team file at \`~/.mumucc/teams/{team-name}/config.json\`
|
|
35
52
|
- A corresponding task list directory at \`~/.mumucc/tasks/{team-name}/\`
|
|
53
|
+
- Optional teammate entries pre-seeded into the team config, including their preferred models
|
|
36
54
|
|
|
37
55
|
## Team Workflow
|
|
38
56
|
|
|
@@ -19,7 +19,14 @@ import { TEAM_DELETE_TOOL_NAME } from './constants.js'
|
|
|
19
19
|
import { getPrompt } from './prompt.js'
|
|
20
20
|
import { renderToolResultMessage, renderToolUseMessage } from './UI.js'
|
|
21
21
|
|
|
22
|
-
const inputSchema = lazySchema(() =>
|
|
22
|
+
const inputSchema = lazySchema(() =>
|
|
23
|
+
z.strictObject({
|
|
24
|
+
team_name: z
|
|
25
|
+
.string()
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('Optional explicit team name to delete. Falls back to current team context.'),
|
|
28
|
+
}),
|
|
29
|
+
)
|
|
23
30
|
type InputSchema = ReturnType<typeof inputSchema>
|
|
24
31
|
|
|
25
32
|
export type Output = {
|
|
@@ -69,10 +76,10 @@ export const TeamDeleteTool: Tool<InputSchema, Output> = buildTool({
|
|
|
69
76
|
}
|
|
70
77
|
},
|
|
71
78
|
|
|
72
|
-
async call(
|
|
79
|
+
async call(input, context) {
|
|
73
80
|
const { setAppState, getAppState } = context
|
|
74
81
|
const appState = getAppState()
|
|
75
|
-
const teamName = appState.teamContext?.teamName
|
|
82
|
+
const teamName = input.team_name || appState.teamContext?.teamName
|
|
76
83
|
|
|
77
84
|
if (teamName) {
|
|
78
85
|
// Read team config to check for active members
|