agent-composer 0.1.14 → 0.2.0

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.
Files changed (41) hide show
  1. package/README.md +62 -15
  2. package/composer.config.schema.json +24 -1
  3. package/dist/cli/dispatch-hint.d.ts +2 -0
  4. package/dist/cli/dispatch-hint.js +63 -0
  5. package/dist/cli/dispatch-hint.js.map +1 -0
  6. package/dist/cli/init.js +41 -2
  7. package/dist/cli/init.js.map +1 -1
  8. package/dist/cli/install-plugin.d.ts +3 -2
  9. package/dist/cli/install-plugin.js +19 -7
  10. package/dist/cli/install-plugin.js.map +1 -1
  11. package/dist/config/schema.d.ts +44 -0
  12. package/dist/config/schema.js +12 -1
  13. package/dist/config/schema.js.map +1 -1
  14. package/dist/index.js +1 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/providers/CLIProvider.d.ts +16 -0
  17. package/dist/providers/CLIProvider.js +117 -3
  18. package/dist/providers/CLIProvider.js.map +1 -1
  19. package/dist/providers/IProvider.d.ts +1 -0
  20. package/dist/registry.js +4 -0
  21. package/dist/registry.js.map +1 -1
  22. package/dist/server.d.ts +6 -1
  23. package/dist/server.js +129 -15
  24. package/dist/server.js.map +1 -1
  25. package/dist/util/dispatchHint.d.ts +35 -0
  26. package/dist/util/dispatchHint.js +179 -0
  27. package/dist/util/dispatchHint.js.map +1 -0
  28. package/dist/util/handoff.d.ts +58 -0
  29. package/dist/util/handoff.js +107 -0
  30. package/dist/util/handoff.js.map +1 -0
  31. package/dist/util/projectToolResult.d.ts +13 -0
  32. package/dist/util/projectToolResult.js +169 -0
  33. package/dist/util/projectToolResult.js.map +1 -0
  34. package/package.json +3 -2
  35. package/plugin/composer-mastermind/README.md +11 -6
  36. package/plugin/composer-mastermind/agents/coder.md +8 -7
  37. package/plugin/composer-mastermind/agents/reviewer-claude.md +31 -0
  38. package/plugin/composer-mastermind/hooks/boundary_guard.sh +7 -4
  39. package/plugin/composer-mastermind/hooks/lint-on-save.sh +1 -1
  40. package/plugin/composer-mastermind/plugin.json +3 -2
  41. package/plugin/composer-mastermind/skills/composer-mastermind/SKILL.md +30 -18
@@ -0,0 +1,35 @@
1
+ export type Tier = "cheap" | "premium";
2
+ export type Reasoning = "none" | "low" | "high";
3
+ export type PromptSize = "lite" | "full";
4
+ export interface DispatchSignals {
5
+ promptChars: number;
6
+ estOutputTokens: number;
7
+ hasCode: boolean;
8
+ hasFileRef: boolean;
9
+ hasDestructive: boolean;
10
+ complexityScore: number;
11
+ isReviewWithInlineDiff: boolean;
12
+ }
13
+ export interface DispatchHint {
14
+ tier: Tier;
15
+ reasoning: Reasoning;
16
+ promptSize: PromptSize;
17
+ recommendDispatch: boolean;
18
+ rationale: string;
19
+ signals: DispatchSignals;
20
+ }
21
+ export interface ClassifyInput {
22
+ prompt: string;
23
+ subagentType?: string;
24
+ description?: string;
25
+ }
26
+ export interface WorkerPromptParts {
27
+ objective: string;
28
+ files?: string[];
29
+ constraints?: string[];
30
+ acceptance?: string[];
31
+ brief?: string;
32
+ }
33
+ export declare function classifyDispatch(input: ClassifyInput): DispatchHint;
34
+ export declare function neutralDispatchHint(): DispatchHint;
35
+ export declare function buildWorkerPrompt(hint: DispatchHint, parts: WorkerPromptParts): string;
@@ -0,0 +1,179 @@
1
+ import { z } from "zod";
2
+ const ClassifyInputSchema = z.object({
3
+ prompt: z.string(),
4
+ subagentType: z.string().optional(),
5
+ description: z.string().optional(),
6
+ });
7
+ const WorkerPromptPartsSchema = z.object({
8
+ objective: z.string().min(1),
9
+ files: z.array(z.string()).optional(),
10
+ constraints: z.array(z.string()).optional(),
11
+ acceptance: z.array(z.string()).optional(),
12
+ brief: z.string().optional(),
13
+ });
14
+ const CODE_KEYWORD = /\b(?:function|class|const|let|import|export|def)\b|=>/;
15
+ const FILE_REF = /(\.[a-z0-9]{1,5}\b|src\/|tests\/|lib\/|app\/)[A-Za-z0-9._/-]*(:\d+)?/i;
16
+ const DESTRUCTIVE = /(?:\brm\s+-rf\b|\bdrop\s+table\b|\bdelete\s+from\b|\btruncate\b|\breset\s+--hard\b|--force\b|\bdestroy\b)/i;
17
+ const SENSITIVE = /security|auth|crypto|payment/i;
18
+ const REVIEW = /\b(review|audit)\b/i;
19
+ const DIFF_OR_CODE_BLOCK = /```|^diff --git |^@@ |^(?:---|\+\+\+) /m;
20
+ const HIGH_COMPLEXITY_TERMS = [
21
+ /\brefactor(?:ing|s|ed)?\b/i,
22
+ /\bmigrat(?:e|es|ed|ing|ion|ions)\b/i,
23
+ /\barchitecture\b/i,
24
+ /\bredesign(?:ing|s|ed)?\b/i,
25
+ /\bmulti[- ]file\b/i,
26
+ /\bend[- ]to[- ]end\b/i,
27
+ /\bschema\b/i,
28
+ /\bconcurrency\b/i,
29
+ /\brewrite(?:s|ing|n)?\b/i,
30
+ ];
31
+ const LOW_COMPLEXITY_TERMS = [
32
+ /\btypo\b/i,
33
+ /\brename(?:s|d|ing)?\b/i,
34
+ /\bformat(?:s|ted|ting)?\b/i,
35
+ /\bcomment(?:s|ed|ing)?\b/i,
36
+ /\bbump(?:s|ed|ing)?\b/i,
37
+ /\bone[- ]line\b/i,
38
+ /\btrivial\b/i,
39
+ ];
40
+ export function classifyDispatch(input) {
41
+ const validated = ClassifyInputSchema.parse(input);
42
+ const prompt = validated.prompt;
43
+ const description = validated.description ?? "";
44
+ const promptChars = prompt.length;
45
+ const hasCode = detectCode(prompt);
46
+ const hasFileRef = FILE_REF.test(prompt);
47
+ const hasDestructive = DESTRUCTIVE.test(prompt);
48
+ const complexityScore = computeComplexityScore(prompt, {
49
+ hasCode,
50
+ hasFileRef,
51
+ });
52
+ const estOutputTokens = Math.round((promptChars / 4) * (1 + complexityScore * 2)) +
53
+ (hasCode ? 200 : 0);
54
+ const isReviewWithInlineDiff = REVIEW.test(`${description}\n${prompt}`) && DIFF_OR_CODE_BLOCK.test(prompt);
55
+ let recommendDispatch = estOutputTokens > 500 || (hasFileRef && complexityScore > 0.3);
56
+ if (isReviewWithInlineDiff && estOutputTokens <= 600) {
57
+ recommendDispatch = false;
58
+ }
59
+ if (hasDestructive && promptChars < 200) {
60
+ recommendDispatch = false;
61
+ }
62
+ const sensitive = SENSITIVE.test(`${description}\n${prompt}`);
63
+ const tier = complexityScore >= 0.6 || promptChars > 2000 || sensitive
64
+ ? "premium"
65
+ : "cheap";
66
+ const reasoning = complexityScore >= 0.6 ? "high" : complexityScore >= 0.25 ? "low" : "none";
67
+ const promptSize = complexityScore >= 0.4 || (hasFileRef && estOutputTokens > 800)
68
+ ? "full"
69
+ : "lite";
70
+ const signals = {
71
+ promptChars,
72
+ estOutputTokens,
73
+ hasCode,
74
+ hasFileRef,
75
+ hasDestructive,
76
+ complexityScore,
77
+ isReviewWithInlineDiff,
78
+ };
79
+ return {
80
+ tier,
81
+ reasoning,
82
+ promptSize,
83
+ recommendDispatch,
84
+ rationale: rationaleFor({ recommendDispatch, signals, sensitive }),
85
+ signals,
86
+ };
87
+ }
88
+ export function neutralDispatchHint() {
89
+ return classifyDispatch({ prompt: "" });
90
+ }
91
+ export function buildWorkerPrompt(hint, parts) {
92
+ const validated = WorkerPromptPartsSchema.parse(parts);
93
+ const sections = [formatBlock("Objective", validated.objective)];
94
+ const files = nonEmptyItems(validated.files ?? []);
95
+ if (files.length > 0)
96
+ sections.push(formatList("Files", files));
97
+ if (hint.promptSize === "full") {
98
+ const constraints = nonEmptyItems(validated.constraints ?? []);
99
+ const acceptance = nonEmptyItems(validated.acceptance ?? []);
100
+ const brief = validated.brief ?? "";
101
+ if (constraints.length > 0)
102
+ sections.push(formatList("Constraints", constraints));
103
+ if (acceptance.length > 0)
104
+ sections.push(formatList("Acceptance", acceptance));
105
+ if (brief.trim().length > 0)
106
+ sections.push(formatBlock("Brief", brief));
107
+ }
108
+ return sections.join("\n\n");
109
+ }
110
+ function detectCode(prompt) {
111
+ if (/```/.test(prompt))
112
+ return true;
113
+ if (hasIndentedBlock(prompt))
114
+ return true;
115
+ const matchCount = Array.from(prompt.matchAll(new RegExp(CODE_KEYWORD.source, "g"))).length;
116
+ if (matchCount === 0)
117
+ return false;
118
+ const wordCount = prompt.match(/\b[\w-]+\b/g)?.length ?? 1;
119
+ const density = matchCount / Math.max(1, wordCount);
120
+ return matchCount >= 2 || density >= 0.02;
121
+ }
122
+ function hasIndentedBlock(prompt) {
123
+ for (const line of prompt.split(/\r?\n/)) {
124
+ if (/^(?: {4,}|\t)\S/.test(line)) {
125
+ return true;
126
+ }
127
+ }
128
+ return false;
129
+ }
130
+ function computeComplexityScore(prompt, signals) {
131
+ let score = 0;
132
+ for (const term of HIGH_COMPLEXITY_TERMS) {
133
+ if (term.test(prompt))
134
+ score += 0.3;
135
+ }
136
+ for (const term of LOW_COMPLEXITY_TERMS) {
137
+ if (term.test(prompt))
138
+ score -= 0.2;
139
+ }
140
+ if (signals.hasCode)
141
+ score += 0.15;
142
+ if (signals.hasFileRef)
143
+ score += 0.1;
144
+ if (prompt.length > 1200)
145
+ score += 0.2;
146
+ return roundScore(clamp(score, 0, 1));
147
+ }
148
+ function rationaleFor(input) {
149
+ const { recommendDispatch, signals, sensitive } = input;
150
+ if (signals.hasDestructive && signals.promptChars < 200) {
151
+ return `No dispatch: destructive tiny prompt mirrors guard deny at ${signals.promptChars} chars.`;
152
+ }
153
+ if (signals.isReviewWithInlineDiff && signals.estOutputTokens <= 600) {
154
+ return `No dispatch: inline review carve-out keeps ${signals.estOutputTokens} estimated tokens local.`;
155
+ }
156
+ if (recommendDispatch) {
157
+ return `Dispatch: estimated ${signals.estOutputTokens} tokens with complexity ${signals.complexityScore} and fileRef=${signals.hasFileRef}.`;
158
+ }
159
+ if (sensitive) {
160
+ return `No dispatch: sensitive keyword selects premium tier while estimate stays ${signals.estOutputTokens} tokens.`;
161
+ }
162
+ return `No dispatch: estimated ${signals.estOutputTokens} tokens, complexity ${signals.complexityScore}, fileRef=${signals.hasFileRef}.`;
163
+ }
164
+ function nonEmptyItems(items) {
165
+ return items.filter((item) => item.trim().length > 0);
166
+ }
167
+ function formatBlock(label, body) {
168
+ return `${label}:\n${body}`;
169
+ }
170
+ function formatList(label, items) {
171
+ return `${label}:\n${items.map((item) => `- ${item}`).join("\n")}`;
172
+ }
173
+ function clamp(value, min, max) {
174
+ return Math.min(max, Math.max(min, value));
175
+ }
176
+ function roundScore(value) {
177
+ return Math.round(value * 100) / 100;
178
+ }
179
+ //# sourceMappingURL=dispatchHint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatchHint.js","sourceRoot":"","sources":["../../src/util/dispatchHint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { z } from "zod";
2
+ export declare const HANDOFF_DIR = ".composer/handoffs";
3
+ export declare const HANDOFF_VERSION = 1;
4
+ export declare const HandoffArtifactSchema: z.ZodObject<{
5
+ kind: z.ZodEnum<{
6
+ research: "research";
7
+ code: "code";
8
+ review: "review";
9
+ test: "test";
10
+ note: "note";
11
+ }>;
12
+ summary: z.ZodString;
13
+ path: z.ZodOptional<z.ZodString>;
14
+ source: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strip>;
16
+ export declare const HandoffPacketSchema: z.ZodObject<{
17
+ version: z.ZodLiteral<1>;
18
+ runId: z.ZodString;
19
+ createdAt: z.ZodString;
20
+ updatedAt: z.ZodString;
21
+ objective: z.ZodString;
22
+ contextSummary: z.ZodOptional<z.ZodString>;
23
+ constraints: z.ZodArray<z.ZodString>;
24
+ relevantFiles: z.ZodArray<z.ZodString>;
25
+ acceptanceCriteria: z.ZodArray<z.ZodString>;
26
+ decisions: z.ZodArray<z.ZodString>;
27
+ openQuestions: z.ZodArray<z.ZodString>;
28
+ artifacts: z.ZodArray<z.ZodObject<{
29
+ kind: z.ZodEnum<{
30
+ research: "research";
31
+ code: "code";
32
+ review: "review";
33
+ test: "test";
34
+ note: "note";
35
+ }>;
36
+ summary: z.ZodString;
37
+ path: z.ZodOptional<z.ZodString>;
38
+ source: z.ZodOptional<z.ZodString>;
39
+ }, z.core.$strip>>;
40
+ briefPath: z.ZodOptional<z.ZodString>;
41
+ }, z.core.$strip>;
42
+ export type HandoffArtifact = z.infer<typeof HandoffArtifactSchema>;
43
+ export type HandoffPacket = z.infer<typeof HandoffPacketSchema>;
44
+ export interface NewHandoffPacketInput {
45
+ objective: string;
46
+ contextSummary?: string;
47
+ constraints?: string[];
48
+ relevantFiles?: string[];
49
+ acceptanceCriteria?: string[];
50
+ decisions?: string[];
51
+ openQuestions?: string[];
52
+ artifacts?: HandoffArtifact[];
53
+ briefPath?: string;
54
+ }
55
+ export declare function newHandoffPacket(input: NewHandoffPacketInput): HandoffPacket;
56
+ export declare function writeHandoffPacket(packet: HandoffPacket, dir?: string): string;
57
+ export declare function readHandoffPacket(handoffPath: string, root?: string): HandoffPacket;
58
+ export declare function formatHandoffForPrompt(packet: HandoffPacket): string;
@@ -0,0 +1,107 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdirSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { z } from "zod";
5
+ export const HANDOFF_DIR = ".composer/handoffs";
6
+ export const HANDOFF_VERSION = 1;
7
+ export const HandoffArtifactSchema = z.object({
8
+ kind: z.enum(["research", "code", "review", "test", "note"]),
9
+ summary: z.string().min(1),
10
+ path: z.string().min(1).optional(),
11
+ source: z.string().min(1).optional(),
12
+ });
13
+ export const HandoffPacketSchema = z.object({
14
+ version: z.literal(HANDOFF_VERSION),
15
+ runId: z.string().uuid(),
16
+ createdAt: z.string().datetime(),
17
+ updatedAt: z.string().datetime(),
18
+ objective: z.string().min(1),
19
+ contextSummary: z.string().min(1).optional(),
20
+ constraints: z.array(z.string().min(1)),
21
+ relevantFiles: z.array(z.string().min(1)),
22
+ acceptanceCriteria: z.array(z.string().min(1)),
23
+ decisions: z.array(z.string().min(1)),
24
+ openQuestions: z.array(z.string().min(1)),
25
+ artifacts: z.array(HandoffArtifactSchema),
26
+ briefPath: z.string().min(1).optional(),
27
+ });
28
+ export function newHandoffPacket(input) {
29
+ const now = new Date().toISOString();
30
+ return HandoffPacketSchema.parse({
31
+ version: HANDOFF_VERSION,
32
+ runId: randomUUID(),
33
+ createdAt: now,
34
+ updatedAt: now,
35
+ objective: input.objective,
36
+ contextSummary: input.contextSummary,
37
+ constraints: input.constraints ?? [],
38
+ relevantFiles: input.relevantFiles ?? [],
39
+ acceptanceCriteria: input.acceptanceCriteria ?? [],
40
+ decisions: input.decisions ?? [],
41
+ openQuestions: input.openQuestions ?? [],
42
+ artifacts: input.artifacts ?? [],
43
+ briefPath: input.briefPath,
44
+ });
45
+ }
46
+ export function writeHandoffPacket(packet, dir = HANDOFF_DIR) {
47
+ const validated = HandoffPacketSchema.parse(packet);
48
+ const absDir = resolve(dir);
49
+ mkdirSync(absDir, { recursive: true });
50
+ const filePath = resolve(absDir, `${validated.runId}.json`);
51
+ writeFileSync(filePath, `${JSON.stringify(validated, null, 2)}\n`, "utf8");
52
+ return filePath;
53
+ }
54
+ export function readHandoffPacket(handoffPath, root = process.cwd()) {
55
+ const absRoot = resolve(root);
56
+ const absHandoffDir = resolve(absRoot, HANDOFF_DIR);
57
+ const absPath = resolve(absRoot, handoffPath);
58
+ if (!isInside(absHandoffDir, absPath)) {
59
+ throw new Error(`handoffPath must resolve under ${HANDOFF_DIR}; got ${handoffPath}`);
60
+ }
61
+ const realHandoffDir = realpathSync(absHandoffDir);
62
+ const realPath = realpathSync(absPath);
63
+ if (!isInside(realHandoffDir, realPath)) {
64
+ throw new Error(`handoffPath must resolve under ${HANDOFF_DIR}; got ${handoffPath}`);
65
+ }
66
+ const raw = readFileSync(realPath, "utf8");
67
+ return HandoffPacketSchema.parse(JSON.parse(raw));
68
+ }
69
+ export function formatHandoffForPrompt(packet) {
70
+ const lines = [
71
+ "Shared handoff:",
72
+ `- runId: ${packet.runId}`,
73
+ `- objective: ${packet.objective}`,
74
+ ];
75
+ if (packet.contextSummary)
76
+ lines.push(`- context: ${packet.contextSummary}`);
77
+ pushList(lines, "constraints", packet.constraints);
78
+ pushList(lines, "relevantFiles", packet.relevantFiles);
79
+ pushList(lines, "acceptanceCriteria", packet.acceptanceCriteria);
80
+ pushList(lines, "decisions", packet.decisions);
81
+ pushList(lines, "openQuestions", packet.openQuestions);
82
+ if (packet.briefPath)
83
+ lines.push(`- briefPath: ${packet.briefPath}`);
84
+ if (packet.artifacts.length > 0) {
85
+ lines.push("- artifacts:");
86
+ for (const artifact of packet.artifacts) {
87
+ const source = artifact.source ? ` (${artifact.source})` : "";
88
+ const path = artifact.path ? ` [${artifact.path}]` : "";
89
+ lines.push(` - ${artifact.kind}${source}${path}: ${artifact.summary}`);
90
+ }
91
+ }
92
+ return lines.join("\n");
93
+ }
94
+ function pushList(lines, label, values) {
95
+ if (values.length === 0)
96
+ return;
97
+ lines.push(`- ${label}:`);
98
+ for (const value of values) {
99
+ lines.push(` - ${value}`);
100
+ }
101
+ }
102
+ function isInside(parent, child) {
103
+ const normalizedParent = parent.endsWith("/") ? parent : `${parent}/`;
104
+ const normalizedChild = child.endsWith("/") ? child : child;
105
+ return normalizedChild === parent || normalizedChild.startsWith(normalizedParent);
106
+ }
107
+ //# sourceMappingURL=handoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.js","sourceRoot":"","sources":["../../src/util/handoff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface ProjectOptions {
2
+ maxChars?: number;
3
+ headChars?: number;
4
+ tailChars?: number;
5
+ }
6
+ export interface ProjectResult {
7
+ text: string;
8
+ projected: boolean;
9
+ originalChars: number;
10
+ keptChars: number;
11
+ kind: "json" | "diff" | "log" | "generic";
12
+ }
13
+ export declare function projectToolResult(input: string, opts?: ProjectOptions): ProjectResult;
@@ -0,0 +1,169 @@
1
+ const DEFAULT_MAX_CHARS = 16_000;
2
+ const PROJECTED_MARKER = /(?:^|\n)… \[elided \d+ chars \/ \d+ lines\] …(?:\n|$)/;
3
+ const JSON_PREFIX = "[projected JSON:";
4
+ const LOG_LINE = /^(?:\s*(?:PASS\b|FAIL\b|✓|✗|Error\b)|[^:\n]+:\d+:\d+\b|\s+at [^\n]+:\d+(?::\d+)?\b)/;
5
+ export function projectToolResult(input, opts = {}) {
6
+ if (typeof input !== "string") {
7
+ throw new Error("projectToolResult: input must be a string");
8
+ }
9
+ const options = normalizeOptions(opts);
10
+ const kind = detectKind(input);
11
+ if (input.length === 0 || input.length <= options.maxChars || isAlreadyProjected(input)) {
12
+ return {
13
+ text: input,
14
+ projected: false,
15
+ originalChars: input.length,
16
+ keptChars: input.length,
17
+ kind,
18
+ };
19
+ }
20
+ const text = kind === "json"
21
+ ? projectJson(input, options.maxChars)
22
+ : projectText(input, options.headChars, options.tailChars);
23
+ return {
24
+ text,
25
+ projected: true,
26
+ originalChars: input.length,
27
+ keptChars: text.length,
28
+ kind,
29
+ };
30
+ }
31
+ function normalizeOptions(opts) {
32
+ const maxChars = normalizeLimit("maxChars", opts.maxChars, DEFAULT_MAX_CHARS);
33
+ const defaultHeadChars = Math.round(maxChars * 0.6);
34
+ const defaultTailChars = Math.round(maxChars * 0.25);
35
+ const headChars = normalizeLimit("headChars", opts.headChars, defaultHeadChars, true);
36
+ const tailChars = normalizeLimit("tailChars", opts.tailChars, defaultTailChars, true);
37
+ return { maxChars, headChars, tailChars };
38
+ }
39
+ function normalizeLimit(name, value, fallback, allowZero = false) {
40
+ const raw = value ?? fallback;
41
+ if (raw === Number.POSITIVE_INFINITY)
42
+ return Number.MAX_SAFE_INTEGER;
43
+ if (!Number.isFinite(raw)) {
44
+ throw new Error(`projectToolResult: ${name} must be a finite number`);
45
+ }
46
+ const rounded = Math.round(raw);
47
+ if (rounded < 0 || (!allowZero && rounded === 0)) {
48
+ const expectation = allowZero ? "non-negative" : "positive";
49
+ throw new Error(`projectToolResult: ${name} must be ${expectation}`);
50
+ }
51
+ return rounded;
52
+ }
53
+ function isAlreadyProjected(input) {
54
+ return input.startsWith(JSON_PREFIX) || PROJECTED_MARKER.test(input);
55
+ }
56
+ function detectKind(input) {
57
+ const trimmed = input.trim();
58
+ if (trimmed.length > 0 && (trimmed.startsWith("{") || trimmed.startsWith("["))) {
59
+ try {
60
+ JSON.parse(trimmed);
61
+ return "json";
62
+ }
63
+ catch {
64
+ // Invalid JSON still falls through to text heuristics.
65
+ }
66
+ }
67
+ if (looksLikeDiff(input))
68
+ return "diff";
69
+ if (looksLikeLog(input))
70
+ return "log";
71
+ return "generic";
72
+ }
73
+ function looksLikeDiff(input) {
74
+ if (/^diff --git /m.test(input) || /^@@ /m.test(input))
75
+ return true;
76
+ const plusMinusLines = input
77
+ .split("\n")
78
+ .filter((line) => /^[+-]/.test(line)).length;
79
+ return plusMinusLines >= 6;
80
+ }
81
+ function looksLikeLog(input) {
82
+ return input.split("\n").some((line) => LOG_LINE.test(line));
83
+ }
84
+ function projectText(input, headChars, tailChars) {
85
+ const collapsed = collapseRepeatedLines(input);
86
+ const head = collapsed.slice(0, headChars);
87
+ const tailStart = tailChars === 0
88
+ ? collapsed.length
89
+ : Math.max(head.length, collapsed.length - tailChars);
90
+ const middle = collapsed.slice(head.length, tailStart);
91
+ const tail = collapsed.slice(tailStart);
92
+ const marker = `\n… [elided ${middle.length} chars / ${countLines(middle)} lines] …\n`;
93
+ return `${head}${marker}${tail}`;
94
+ }
95
+ function collapseRepeatedLines(input) {
96
+ const lines = input.split("\n");
97
+ const collapsed = [];
98
+ for (let index = 0; index < lines.length;) {
99
+ const line = lines[index] ?? "";
100
+ let count = 1;
101
+ while (index + count < lines.length && lines[index + count] === line) {
102
+ count++;
103
+ }
104
+ collapsed.push(count > 3 ? `${line} … (×${count})` : lines.slice(index, index + count).join("\n"));
105
+ index += count;
106
+ }
107
+ return collapsed.join("\n");
108
+ }
109
+ function countLines(input) {
110
+ if (input.length === 0)
111
+ return 0;
112
+ return input.split("\n").length;
113
+ }
114
+ function projectJson(input, maxChars) {
115
+ const parsed = JSON.parse(input.trim());
116
+ const summary = summarizeJson(parsed);
117
+ const sample = JSON.stringify(sampleJson(parsed), null, 2) ?? "";
118
+ const prefix = `${JSON_PREFIX} ${summary}]\n`;
119
+ if (prefix.length >= maxChars) {
120
+ return `${prefix.slice(0, Math.max(0, maxChars - 1))}…`;
121
+ }
122
+ const remaining = maxChars - prefix.length;
123
+ return `${prefix}${truncate(sample, remaining)}`;
124
+ }
125
+ function summarizeJson(value, depth = 0) {
126
+ if (value === null)
127
+ return "null";
128
+ if (Array.isArray(value)) {
129
+ if (value.length === 0)
130
+ return "array(length=0)";
131
+ if (depth >= 3)
132
+ return `array(length=${value.length})`;
133
+ return `array(length=${value.length}, sample=${summarizeJson(value[0], depth + 1)})`;
134
+ }
135
+ if (typeof value === "object") {
136
+ const entries = Object.entries(value);
137
+ if (entries.length === 0)
138
+ return "object{}";
139
+ if (depth >= 3)
140
+ return `object(keys=${entries.length})`;
141
+ const visibleEntries = entries.slice(0, 8).map(([key, entryValue]) => `${key}:${summarizeJson(entryValue, depth + 1)}`);
142
+ const hidden = entries.length - visibleEntries.length;
143
+ const suffix = hidden > 0 ? `,…+${hidden} keys` : "";
144
+ return `object{${visibleEntries.join(",")}${suffix}}`;
145
+ }
146
+ return typeof value;
147
+ }
148
+ function sampleJson(value, depth = 0) {
149
+ if (value === null || typeof value !== "object")
150
+ return value;
151
+ if (depth >= 3)
152
+ return Array.isArray(value) ? [] : {};
153
+ if (Array.isArray(value)) {
154
+ return value.length > 0 ? [sampleJson(value[0], depth + 1)] : [];
155
+ }
156
+ return Object.fromEntries(Object.entries(value)
157
+ .slice(0, 8)
158
+ .map(([key, entryValue]) => [key, sampleJson(entryValue, depth + 1)]));
159
+ }
160
+ function truncate(input, maxChars) {
161
+ if (maxChars <= 0)
162
+ return "";
163
+ if (input.length <= maxChars)
164
+ return input;
165
+ if (maxChars === 1)
166
+ return "…";
167
+ return `${input.slice(0, maxChars - 1)}…`;
168
+ }
169
+ //# sourceMappingURL=projectToolResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectToolResult.js","sourceRoot":"","sources":["../../src/util/projectToolResult.ts"],"names":[],"mappings":"AAgBA,MAAM,iBAAiB,GAAG,MAAM,CAAC;AACjC,MAAM,gBAAgB,GAAG,uDAAuD,CAAC;AACjF,MAAM,WAAW,GAAG,kBAAkB,CAAC;AACvC,MAAM,QAAQ,GAAG,qFAAqF,CAAC;AAQvG,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,OAAuB,EAAE;IAEzB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACxF,OAAO;YACL,IAAI,EAAE,KAAK;YACX,SAAS,EAAE,KAAK;YAChB,aAAa,EAAE,KAAK,CAAC,MAAM;YAC3B,SAAS,EAAE,KAAK,CAAC,MAAM;YACvB,IAAI;SACL,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GACR,IAAI,KAAK,MAAM;QACb,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC;QACtC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAE/D,OAAO;QACL,IAAI;QACJ,SAAS,EAAE,IAAI;QACf,aAAa,EAAE,KAAK,CAAC,MAAM;QAC3B,SAAS,EAAE,IAAI,CAAC,MAAM;QACtB,IAAI;KACL,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAoB;IAC5C,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAC;IAC9E,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC;IACpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;IACtF,MAAM,SAAS,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;IAEtF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC5C,CAAC;AAED,SAAS,cAAc,CACrB,IAAY,EACZ,KAAyB,EACzB,QAAgB,EAChB,SAAS,GAAG,KAAK;IAEjB,MAAM,GAAG,GAAG,KAAK,IAAI,QAAQ,CAAC;IAC9B,IAAI,GAAG,KAAK,MAAM,CAAC,iBAAiB;QAAE,OAAO,MAAM,CAAC,gBAAgB,CAAC;IACrE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,0BAA0B,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,SAAS,IAAI,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,YAAY,WAAW,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC/E,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpB,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC;IAED,IAAI,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACxC,IAAI,YAAY,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpE,MAAM,cAAc,GAAG,KAAK;SACzB,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/C,OAAO,cAAc,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,WAAW,CAAC,KAAa,EAAE,SAAiB,EAAE,SAAiB;IACtE,MAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,SAAS,KAAK,CAAC;QAC/B,CAAC,CAAC,SAAS,CAAC,MAAM;QAClB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,eAAe,MAAM,CAAC,MAAM,YAAY,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC;IACvF,OAAO,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC;AACnC,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC;QAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,OAAO,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;YACrE,KAAK,EAAE,CAAC;QACV,CAAC;QACD,SAAS,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACnG,KAAK,IAAI,KAAK,CAAC;IACjB,CAAC;IAED,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACjC,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;AAClC,CAAC;AAED,SAAS,WAAW,CAAC,KAAa,EAAE,QAAgB;IAClD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAY,CAAC;IACnD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjE,MAAM,MAAM,GAAG,GAAG,WAAW,IAAI,OAAO,KAAK,CAAC;IAC9C,IAAI,MAAM,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1D,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;AACnD,CAAC;AAED,SAAS,aAAa,CAAC,KAAc,EAAE,KAAK,GAAG,CAAC;IAC9C,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,iBAAiB,CAAC;QACjD,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO,gBAAgB,KAAK,CAAC,MAAM,GAAG,CAAC;QACvD,OAAO,gBAAgB,KAAK,CAAC,MAAM,YAAY,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC;IACvF,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,CAAC;QACjE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC;QAC5C,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO,eAAe,OAAO,CAAC,MAAM,GAAG,CAAC;QACxD,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAC5C,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,aAAa,CAAC,UAAU,EAAE,KAAK,GAAG,CAAC,CAAC,EAAE,CACxE,CAAC;QACF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,OAAO,UAAU,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC;IACxD,CAAC;IACD,OAAO,OAAO,KAAK,CAAC;AACtB,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,KAAK,GAAG,CAAC;IAC3C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9D,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,CAAC;IAED,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC;SAC7C,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,UAAU,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CACxE,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,KAAa,EAAE,QAAgB;IAC/C,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7B,IAAI,KAAK,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAC/B,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC;AAC5C,CAAC"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "agent-composer",
3
- "version": "0.1.14",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
- "description": "Multi-agent orchestration MCP server. Claude orchestrates; GLM and agy do the work.",
5
+ "description": "Multi-agent orchestration MCP server. Claude orchestrates; GLM, Codex, and agy do the work.",
6
6
  "bin": {
7
7
  "agent-composer": "./dist/index.js"
8
8
  },
@@ -32,6 +32,7 @@
32
32
  "test:hooks": "bash tests/hooks/run.sh",
33
33
  "test:scripts": "bash tests/scripts/run.sh",
34
34
  "test:all": "npm run test && npm run test:hooks && npm run test:scripts",
35
+ "eval:routes": "tsx evals/scripts/route-compare.ts",
35
36
  "usage": "npx -y ccusage daily",
36
37
  "schema:lint": "ajv compile --strict=true -c ajv-formats -s composer.config.schema.json && ajv validate --strict=false -c ajv-formats -s composer.config.schema.json -d composer.config.json && ajv compile --strict=true -s plugin.schema.json && ajv validate --strict=true -s plugin.schema.json -d 'plugin/*/plugin.json'",
37
38
  "prepublishOnly": "npm run lint && npm run test && npm run build && npm run schema:lint"
@@ -1,18 +1,22 @@
1
1
  # composer-mastermind
2
2
 
3
- > Multi-agent orchestrator plugin for Claude Code. Claude orchestrates; GLM and agy execute.
3
+ > Multi-agent orchestrator plugin for Claude Code. Claude orchestrates; GLM, Codex, and agy execute. Claude Code CLI is available as a premium review escalation.
4
4
 
5
5
  ## What it is
6
6
 
7
- Composer-mastermind is a Claude Code plugin that turns the main session into a coordinator. The orchestrator never writes code, runs bash, or edits files directly — instead it dispatches work through three subagents wired to the `agent-composer` MCP server:
7
+ Composer-mastermind is a Claude Code plugin that turns the main session into a coordinator. The orchestrator never writes code, runs bash, or edits files directly — instead it dispatches work through subagents and direct apply tools wired to the `agent-composer` MCP server:
8
8
 
9
9
  | Subagent | Tool | Role |
10
10
  |---|---|---|
11
- | `coder` | `mcp__composer__composer_code` | Writes code via GLM (Anthropic-compatible endpoint) |
12
- | `researcher` | `mcp__composer__composer_research` | Docs lookup + research via `agy` CLI (Gemini) |
11
+ | direct | `mcp__composer__composer_handoff_create` | Writes shared context packets for multi-provider work |
12
+ | direct | `mcp__composer__composer_code_cli` | Default coding path; CLI executor applies code directly from the MCP server root; configure as Codex or agy |
13
+ | direct | `mcp__composer__composer_code_chain` | GLM-authored fallback; server applies complete-file blocks deterministically |
14
+ | `coder` | `mcp__composer__composer_code` | Patch-only legacy path via GLM (Anthropic-compatible endpoint) |
15
+ | `researcher` | `mcp__composer__composer_research` | Docs lookup + web research via Codex CLI search in read-only mode |
13
16
  | `reviewer` | `mcp__composer__composer_review` | Code review via `agy` CLI |
17
+ | `reviewer-claude` | `mcp__composer__composer_review_claude` | Premium Claude second-opinion review for explicit/risky cases |
14
18
 
15
- The orchestrator's allowed-tool surface is enforced by `boundary_guard.sh` — `Edit`, `Write`, `Bash`, `NotebookEdit` are denied; only the three composer MCP tools plus `Read`/`Glob` pass.
19
+ The orchestrator's allowed-tool surface is enforced by `boundary_guard.sh` — `Edit`, `Update`, `Write`, `Bash`, `NotebookEdit` are denied; composer MCP tools plus `Read`/`Glob` pass.
16
20
 
17
21
  ## What's inside
18
22
 
@@ -23,7 +27,8 @@ composer-mastermind/
23
27
  ├── agents/ # haiku-wrapped subagent defs
24
28
  │ ├── coder.md
25
29
  │ ├── researcher.md
26
- └── reviewer.md
30
+ ├── reviewer.md
31
+ │ └── reviewer-claude.md
27
32
  ├── commands/
28
33
  │ └── evolve.md # /evolve slash command (GEPA loop)
29
34
  └── hooks/