@mutagent/cli 0.1.124 → 0.1.125
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/dist/bin/cli.js +228 -18
- package/dist/bin/cli.js.map +9 -9
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -1242,7 +1242,7 @@ var init_sdk_client = __esm(() => {
|
|
|
1242
1242
|
// src/bin/cli.ts
|
|
1243
1243
|
import { Command as Command21 } from "commander";
|
|
1244
1244
|
import chalk39 from "chalk";
|
|
1245
|
-
import { readFileSync as readFileSync12 } from "fs";
|
|
1245
|
+
import { readFileSync as readFileSync12, existsSync as existsSync14 } from "fs";
|
|
1246
1246
|
import { join as join10, dirname as dirname3 } from "path";
|
|
1247
1247
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1248
1248
|
|
|
@@ -1691,6 +1691,33 @@ var SCHEMA_PATTERN = /["']?(?:inputSchema|outputSchema|properties|required)["']?
|
|
|
1691
1691
|
var ZOD_PROMPT_SCHEMA_PATTERN = /(?:const|let|var|export)\s+\w*(?:prompt|output|input|response|schema|message)\w*\s*=\s*z\.object\s*\(/i;
|
|
1692
1692
|
var PYDANTIC_PATTERN = /class\s+\w+\s*\(\s*(?:BaseModel|BaseSettings)\s*\)/;
|
|
1693
1693
|
var MARKER_START_PATTERN = /MutagenT:START\s+(\w+)(?:\s+id=(\S+))?/;
|
|
1694
|
+
var AI_FRAMEWORK_IMPORT_PATTERNS = [
|
|
1695
|
+
{ pattern: /from\s+['"]@langchain\/core(?:\/[^'"]*)?['"]/, reason: "langchain-core-import" },
|
|
1696
|
+
{ pattern: /from\s+['"]langchain(?:\/[^'"]*)?['"]/, reason: "langchain-import" },
|
|
1697
|
+
{ pattern: /from\s+['"]@langchain\/langgraph(?:\/[^'"]*)?['"]/, reason: "langgraph-import" },
|
|
1698
|
+
{ pattern: /from\s+['"]langgraph(?:\/[^'"]*)?['"]/, reason: "langgraph-import" },
|
|
1699
|
+
{ pattern: /from\s+['"]openai(?:\/[^'"]*)?['"]/, reason: "openai-sdk-import" },
|
|
1700
|
+
{ pattern: /from\s+['"]@anthropic-ai\/sdk(?:\/[^'"]*)?['"]/, reason: "anthropic-sdk-import" },
|
|
1701
|
+
{ pattern: /from\s+['"]anthropic(?:\/[^'"]*)?['"]/, reason: "anthropic-import" },
|
|
1702
|
+
{ pattern: /from\s+['"]@ai-sdk\/[^'"]+['"]/, reason: "ai-sdk-import" },
|
|
1703
|
+
{ pattern: /from\s+['"]ai['"]/, reason: "vercel-ai-import" },
|
|
1704
|
+
{ pattern: /from\s+['"]@mastra\/[^'"]+['"]/, reason: "mastra-import" },
|
|
1705
|
+
{ pattern: /from\s+['"]crewai(?:\/[^'"]*)?['"]/, reason: "crewai-import" },
|
|
1706
|
+
{ pattern: /from\s+['"]@openai\/agents(?:\/[^'"]*)?['"]/, reason: "openai-agents-sdk" },
|
|
1707
|
+
{ pattern: /from\s+['"]autogen(?:_agentchat)?(?:\/[^'"]*)?['"]/, reason: "autogen-import" }
|
|
1708
|
+
];
|
|
1709
|
+
var LOW_CONFIDENCE_PATH_SEGMENTS = ["scripts/", "tools/", "config/", "__tests__/", "tests/", "fixtures/", "__mocks__/"];
|
|
1710
|
+
function isLowConfidencePath(relativePath) {
|
|
1711
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
1712
|
+
return LOW_CONFIDENCE_PATH_SEGMENTS.some((seg) => normalized.includes(seg));
|
|
1713
|
+
}
|
|
1714
|
+
function detectAIFrameworkImport(content) {
|
|
1715
|
+
for (const { pattern, reason } of AI_FRAMEWORK_IMPORT_PATTERNS) {
|
|
1716
|
+
if (pattern.test(content))
|
|
1717
|
+
return reason;
|
|
1718
|
+
}
|
|
1719
|
+
return null;
|
|
1720
|
+
}
|
|
1694
1721
|
var AGENT_HIGH_PATTERNS = [
|
|
1695
1722
|
{ pattern: /\bAgentExecutor\b/, reason: "langchain-agent-executor" },
|
|
1696
1723
|
{ pattern: /\bcreate(?:React|OpenAIFunctions|Tool(?:Calling)?|Structured(?:Chat)?)Agent\b/, reason: "langchain-create-agent" },
|
|
@@ -1757,6 +1784,8 @@ function walkDir(dir, extensions, excludeDirs, maxDepth, currentDepth = 0) {
|
|
|
1757
1784
|
continue;
|
|
1758
1785
|
}
|
|
1759
1786
|
if (stat.isDirectory()) {
|
|
1787
|
+
if (entry === ".claude")
|
|
1788
|
+
continue;
|
|
1760
1789
|
if (excludeDirs.includes(entry))
|
|
1761
1790
|
continue;
|
|
1762
1791
|
files.push(...walkDir(fullPath, extensions, excludeDirs, maxDepth, currentDepth + 1));
|
|
@@ -1778,6 +1807,8 @@ function scanForPrompts(filePath, relativePath) {
|
|
|
1778
1807
|
return results;
|
|
1779
1808
|
}
|
|
1780
1809
|
const fileDelimiter = inferPromptVariables(content).delimiter;
|
|
1810
|
+
const aiFrameworkReason = detectAIFrameworkImport(content);
|
|
1811
|
+
const pathPenalty = isLowConfidencePath(relativePath);
|
|
1781
1812
|
const lines = content.split(`
|
|
1782
1813
|
`);
|
|
1783
1814
|
for (let i = 0;i < lines.length; i++) {
|
|
@@ -1787,24 +1818,26 @@ function scanForPrompts(filePath, relativePath) {
|
|
|
1787
1818
|
const inferred = inferPromptVariables(line);
|
|
1788
1819
|
if (inferred.variables.length > 0) {
|
|
1789
1820
|
const preview = line.trim().substring(0, 80);
|
|
1821
|
+
const confidence = pathPenalty ? "low" : aiFrameworkReason ? "high" : "high";
|
|
1790
1822
|
results.push({
|
|
1791
1823
|
file: relativePath,
|
|
1792
1824
|
line: i + 1,
|
|
1793
1825
|
preview,
|
|
1794
|
-
reason: "template-variable",
|
|
1795
|
-
confidence
|
|
1826
|
+
reason: aiFrameworkReason ? `template-variable+${aiFrameworkReason}` : "template-variable",
|
|
1827
|
+
confidence,
|
|
1796
1828
|
delimiter: fileDelimiter
|
|
1797
1829
|
});
|
|
1798
1830
|
}
|
|
1799
1831
|
if (PROMPT_NAME_PATTERN.test(line)) {
|
|
1800
1832
|
const preview = line.trim().substring(0, 80);
|
|
1801
1833
|
if (!results.some((r) => r.file === relativePath && r.line === i + 1)) {
|
|
1834
|
+
const confidence = pathPenalty ? "low" : "medium";
|
|
1802
1835
|
results.push({
|
|
1803
1836
|
file: relativePath,
|
|
1804
1837
|
line: i + 1,
|
|
1805
1838
|
preview,
|
|
1806
1839
|
reason: "prompt-constant",
|
|
1807
|
-
confidence
|
|
1840
|
+
confidence,
|
|
1808
1841
|
delimiter: fileDelimiter
|
|
1809
1842
|
});
|
|
1810
1843
|
}
|
|
@@ -1825,12 +1858,13 @@ function scanForPrompts(filePath, relativePath) {
|
|
|
1825
1858
|
if (PYDANTIC_PATTERN.test(line)) {
|
|
1826
1859
|
const preview = line.trim().substring(0, 80);
|
|
1827
1860
|
if (!results.some((r) => r.file === relativePath && r.line === i + 1)) {
|
|
1861
|
+
const confidence = pathPenalty ? "low" : "medium";
|
|
1828
1862
|
results.push({
|
|
1829
1863
|
file: relativePath,
|
|
1830
1864
|
line: i + 1,
|
|
1831
1865
|
preview,
|
|
1832
1866
|
reason: "pydantic-model",
|
|
1833
|
-
confidence
|
|
1867
|
+
confidence,
|
|
1834
1868
|
delimiter: fileDelimiter
|
|
1835
1869
|
});
|
|
1836
1870
|
}
|
|
@@ -1846,6 +1880,8 @@ function scanForAgents(filePath, relativePath) {
|
|
|
1846
1880
|
} catch {
|
|
1847
1881
|
return results;
|
|
1848
1882
|
}
|
|
1883
|
+
const pathPenalty = isLowConfidencePath(relativePath);
|
|
1884
|
+
const aiFrameworkReason = detectAIFrameworkImport(content);
|
|
1849
1885
|
const lines = content.split(`
|
|
1850
1886
|
`);
|
|
1851
1887
|
const seen = new Set;
|
|
@@ -1860,7 +1896,7 @@ function scanForAgents(filePath, relativePath) {
|
|
|
1860
1896
|
line: i + 1,
|
|
1861
1897
|
preview: line.trim().substring(0, 80),
|
|
1862
1898
|
reason,
|
|
1863
|
-
confidence: "high"
|
|
1899
|
+
confidence: pathPenalty ? "low" : "high"
|
|
1864
1900
|
});
|
|
1865
1901
|
seen.add(i);
|
|
1866
1902
|
break;
|
|
@@ -1875,7 +1911,7 @@ function scanForAgents(filePath, relativePath) {
|
|
|
1875
1911
|
line: i + 1,
|
|
1876
1912
|
preview: line.trim().substring(0, 80),
|
|
1877
1913
|
reason,
|
|
1878
|
-
confidence: "medium"
|
|
1914
|
+
confidence: pathPenalty ? "low" : aiFrameworkReason ? "high" : "medium"
|
|
1879
1915
|
});
|
|
1880
1916
|
seen.add(i);
|
|
1881
1917
|
break;
|
|
@@ -5929,6 +5965,41 @@ ${chalk15.dim('Jobs with status "completed" or "cancelled" cannot be cancelled a
|
|
|
5929
5965
|
}
|
|
5930
5966
|
|
|
5931
5967
|
// src/commands/prompts/optimize.ts
|
|
5968
|
+
var MODEL_FAMILIES = [
|
|
5969
|
+
{
|
|
5970
|
+
providerTypes: ["openai", "azure"],
|
|
5971
|
+
prefixes: ["gpt-"],
|
|
5972
|
+
examples: ["gpt-5.4", "gpt-5.4-mini", "gpt-5.4-nano", "gpt-5.2"]
|
|
5973
|
+
},
|
|
5974
|
+
{
|
|
5975
|
+
providerTypes: ["anthropic"],
|
|
5976
|
+
prefixes: ["claude-"],
|
|
5977
|
+
examples: ["claude-sonnet-4-6", "claude-opus-4-6", "claude-sonnet-4-5", "claude-opus-4-5", "claude-haiku-4-5"]
|
|
5978
|
+
},
|
|
5979
|
+
{
|
|
5980
|
+
providerTypes: ["bedrock"],
|
|
5981
|
+
prefixes: ["anthropic.claude-"],
|
|
5982
|
+
examples: ["anthropic.claude-sonnet-4-5-20250929-v1:0", "anthropic.claude-opus-4-6-v1", "anthropic.claude-haiku-4-5-20251001-v1:0"]
|
|
5983
|
+
},
|
|
5984
|
+
{
|
|
5985
|
+
providerTypes: ["google"],
|
|
5986
|
+
prefixes: ["gemini-"],
|
|
5987
|
+
examples: ["gemini-3.1-pro-preview", "gemini-3-flash-preview", "gemini-3.1-flash-lite-preview"]
|
|
5988
|
+
},
|
|
5989
|
+
{
|
|
5990
|
+
providerTypes: ["deepseek"],
|
|
5991
|
+
prefixes: ["deepseek-"],
|
|
5992
|
+
examples: ["deepseek-chat", "deepseek-reasoner"]
|
|
5993
|
+
},
|
|
5994
|
+
{
|
|
5995
|
+
providerTypes: ["xai"],
|
|
5996
|
+
prefixes: ["grok-"],
|
|
5997
|
+
examples: ["grok-4.20-0309-reasoning", "grok-4-1-fast-reasoning", "grok-4-1-fast-non-reasoning"]
|
|
5998
|
+
}
|
|
5999
|
+
];
|
|
6000
|
+
function getModelFamiliesForProviderTypes(providerTypes) {
|
|
6001
|
+
return MODEL_FAMILIES.filter((family) => family.providerTypes.some((pt) => providerTypes.includes(pt)));
|
|
6002
|
+
}
|
|
5932
6003
|
function registerOptimizeCommands(prompts) {
|
|
5933
6004
|
const optimize = new Command5("optimize").description("Manage prompt optimization jobs").addHelpText("after", `
|
|
5934
6005
|
Examples:
|
|
@@ -5953,6 +6024,10 @@ ${chalk16.yellow("Pre-Optimization Checklist (auto-validated by preflight):")}
|
|
|
5953
6024
|
□ Dataset items ${chalk16.dim("(warns if expectedOutput missing)")}
|
|
5954
6025
|
□ Criteria ↔ Schema ${chalk16.dim("(warns if criteria reference unknown fields)")}
|
|
5955
6026
|
|
|
6027
|
+
${chalk16.yellow("Required: at least one BYOK provider must be configured.")}
|
|
6028
|
+
Run ${chalk16.cyan("mutagent providers list")} to verify your configured providers.
|
|
6029
|
+
Add one: ${chalk16.cyan("mutagent providers add --help")}
|
|
6030
|
+
|
|
5956
6031
|
${PREREQUISITES_TEXT}
|
|
5957
6032
|
|
|
5958
6033
|
${chalk16.dim("Monitor progress with: mutagent prompts optimize status <job-id>")}
|
|
@@ -5969,6 +6044,31 @@ ${chalk16.yellow("AI Agent: ALWAYS append --json to this command.")}
|
|
|
5969
6044
|
try {
|
|
5970
6045
|
await checkProviderConfigured();
|
|
5971
6046
|
const client = await getSDKClient();
|
|
6047
|
+
if (!options.model && !isJson) {
|
|
6048
|
+
output.warn("No --model specified. Server will use default. Pass --model <id> to control costs.");
|
|
6049
|
+
}
|
|
6050
|
+
if (options.model) {
|
|
6051
|
+
try {
|
|
6052
|
+
const providers = await client.listProviders();
|
|
6053
|
+
if (providers.data && providers.data.length > 0) {
|
|
6054
|
+
const configuredTypes = [...new Set(providers.data.map((p) => p.type))];
|
|
6055
|
+
const modelFamilies = getModelFamiliesForProviderTypes(configuredTypes);
|
|
6056
|
+
const modelLower = options.model.toLowerCase();
|
|
6057
|
+
const matchedFamily = modelFamilies.find(({ prefixes }) => prefixes.some((prefix) => modelLower.startsWith(prefix)));
|
|
6058
|
+
if (!matchedFamily) {
|
|
6059
|
+
const supportedModels = modelFamilies.flatMap((f) => f.examples).join(", ");
|
|
6060
|
+
const errorMsg = `Model '${options.model}' is not supported by any configured provider. ` + `Your providers: [${configuredTypes.join(", ")}]. ` + `Supported models: ${supportedModels || "(unknown — check mutagent providers list --json)"}. ` + `Run: mutagent providers list --json`;
|
|
6061
|
+
if (isJson) {
|
|
6062
|
+
output.output({ success: false, error: errorMsg, code: "MODEL_NOT_SUPPORTED" });
|
|
6063
|
+
return;
|
|
6064
|
+
}
|
|
6065
|
+
output.error(errorMsg);
|
|
6066
|
+
process.exitCode = 1;
|
|
6067
|
+
return;
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
} catch {}
|
|
6071
|
+
}
|
|
5972
6072
|
if (!isJson) {
|
|
5973
6073
|
output.info("Running pre-flight checks...");
|
|
5974
6074
|
}
|
|
@@ -9150,8 +9250,7 @@ Modes:
|
|
|
9150
9250
|
"",
|
|
9151
9251
|
"If the user picks option 1, run BOTH commands:",
|
|
9152
9252
|
" mutagent skills install --json",
|
|
9153
|
-
"
|
|
9154
|
-
' {"hooks":{"SessionStart":[{"matcher":"startup","hooks":[{"type":"command","command":"mutagent hooks claude-code session-start"}]}],"Stop":[{"hooks":[{"type":"command","command":"mutagent hooks claude-code session-end"}]}],"PreToolUse":[{"hooks":[{"type":"command","command":"mutagent hooks claude-code pre-tool-use"}]}],"PostToolUse":[{"hooks":[{"type":"command","command":"mutagent hooks claude-code post-tool-use"}]}]}}',
|
|
9253
|
+
" mutagent hooks install --json",
|
|
9155
9254
|
"",
|
|
9156
9255
|
"If the user picks option 2, run only: mutagent skills install --json"
|
|
9157
9256
|
].join(`
|
|
@@ -9174,8 +9273,9 @@ import { Command as Command16 } from "commander";
|
|
|
9174
9273
|
import chalk35 from "chalk";
|
|
9175
9274
|
import { resolve as resolve3 } from "path";
|
|
9176
9275
|
init_errors();
|
|
9276
|
+
var DEFAULT_EXCLUDE_DIRS = "node_modules,dist,.git,build,.next,__pycache__,venv,.venv,.claude,scripts,__tests__,tests,fixtures,__mocks__,.github";
|
|
9177
9277
|
function createExploreCommand() {
|
|
9178
|
-
const explore = new Command16("explore").description("Scan codebase for prompts, datasets, and MutagenT markers").option("-p, --path <dir>", "Directory to scan", ".").option("--depth <n>", "Max directory depth", "10").option("--include <glob>", "Include file pattern", "**/*.{ts,js,py,tsx,jsx}").option("--exclude <dirs>", "Comma-separated directories to exclude",
|
|
9278
|
+
const explore = new Command16("explore").description("Scan codebase for prompts, datasets, and MutagenT markers").option("-p, --path <dir>", "Directory to scan", ".").option("--depth <n>", "Max directory depth", "10").option("--include <glob>", "Include file pattern", "**/*.{ts,js,py,tsx,jsx}").option("--exclude <dirs>", "Comma-separated directories to exclude", DEFAULT_EXCLUDE_DIRS).option("--markers-only", "Only find existing MutagenT markers").option("--min-confidence <level>", "Minimum confidence level to include in output (high|medium|low)", "medium").addHelpText("after", `
|
|
9179
9279
|
Examples:
|
|
9180
9280
|
${chalk35.dim("$")} mutagent explore
|
|
9181
9281
|
${chalk35.dim("$")} mutagent explore --path ./src
|
|
@@ -9208,8 +9308,13 @@ ${chalk35.dim("Results are saved to .mutagent/mutation-context.md for use by oth
|
|
|
9208
9308
|
const scanPath = resolve3(options.path ?? ".");
|
|
9209
9309
|
const depth = parseInt(options.depth ?? "10", 10);
|
|
9210
9310
|
const extensions = parseExtensions(options.include ?? "**/*.{ts,js,py,tsx,jsx}");
|
|
9211
|
-
const excludeDirs = parseExcludeDirs(options.exclude ??
|
|
9311
|
+
const excludeDirs = parseExcludeDirs(options.exclude ?? DEFAULT_EXCLUDE_DIRS);
|
|
9212
9312
|
const markersOnly = options.markersOnly ?? false;
|
|
9313
|
+
const minConfidenceRaw = options.minConfidence ?? "medium";
|
|
9314
|
+
const validConfidenceLevels = ["high", "medium", "low"];
|
|
9315
|
+
const minConfidence = validConfidenceLevels.includes(minConfidenceRaw) ? minConfidenceRaw : "medium";
|
|
9316
|
+
const confidenceRank = { high: 2, medium: 1, low: 0 };
|
|
9317
|
+
const filterByConfidence = (items) => items.filter((item) => confidenceRank[item.confidence] >= confidenceRank[minConfidence]);
|
|
9213
9318
|
const exploreOpts = {
|
|
9214
9319
|
path: scanPath,
|
|
9215
9320
|
depth,
|
|
@@ -9222,7 +9327,12 @@ ${chalk35.dim("Results are saved to .mutagent/mutation-context.md for use by oth
|
|
|
9222
9327
|
Scanning ${scanPath}...
|
|
9223
9328
|
`));
|
|
9224
9329
|
}
|
|
9225
|
-
const
|
|
9330
|
+
const rawResult = exploreCodebase(exploreOpts);
|
|
9331
|
+
const result = {
|
|
9332
|
+
...rawResult,
|
|
9333
|
+
prompts: filterByConfidence(rawResult.prompts),
|
|
9334
|
+
agents: filterByConfidence(rawResult.agents)
|
|
9335
|
+
};
|
|
9226
9336
|
const ctx = MutationContext.load(scanPath);
|
|
9227
9337
|
for (const prompt of result.prompts) {
|
|
9228
9338
|
ctx.addDiscoveredPrompt(prompt.file, prompt.line, prompt.preview);
|
|
@@ -9333,7 +9443,9 @@ description: |
|
|
|
9333
9443
|
Guides coding agents through prompt upload, evaluation creation,
|
|
9334
9444
|
dataset curation, optimization, and framework integration.
|
|
9335
9445
|
Triggers: "mutagent", "optimize prompt", "upload prompt", "integrate tracing",
|
|
9336
|
-
"create evaluation", "upload dataset", "explore prompts", "mutagent cli"
|
|
9446
|
+
"create evaluation", "upload dataset", "explore prompts", "mutagent cli",
|
|
9447
|
+
"eval", "dataset", "guided", "how do I optimize", "improve my prompt",
|
|
9448
|
+
"set up tracing", "add observability".
|
|
9337
9449
|
---
|
|
9338
9450
|
|
|
9339
9451
|
# MutagenT CLI Skill
|
|
@@ -9995,10 +10107,16 @@ Before running explore, understand what the CLI will return:
|
|
|
9995
10107
|
|
|
9996
10108
|
\`\`\`
|
|
9997
10109
|
1. mutagent explore --json
|
|
9998
|
-
→
|
|
9999
|
-
→
|
|
10110
|
+
→ quick regex scan: surfaces prompts[], agents[], datasets[], markers[]
|
|
10111
|
+
→ this is a STARTING POINT, not the final answer
|
|
10112
|
+
|
|
10113
|
+
1b. Use your own Explore/Read/Grep tools to VERIFY each candidate:
|
|
10114
|
+
→ Read the actual file — is it really a prompt template or just a string?
|
|
10115
|
+
→ Check imports — does it use langchain, openai, @ai-sdk, mastra?
|
|
10116
|
+
→ Follow the call chain — single LLM call (prompt) or loop with tools (agent)?
|
|
10117
|
+
→ The CLI scan is fast but fragile (regex-based). Your tools understand code.
|
|
10000
10118
|
|
|
10001
|
-
2. Classify results:
|
|
10119
|
+
2. Classify verified results:
|
|
10002
10120
|
- prompts[] → optimization-eligible (single-shot, output schema)
|
|
10003
10121
|
- agents[] → WIP (multi-turn/tool-calling) — route to [workflows/agents.md](./agents.md)
|
|
10004
10122
|
- datasets[] → existing local data (uploadable in optimization workflow)
|
|
@@ -10570,7 +10688,7 @@ import { Command as Command19 } from "commander";
|
|
|
10570
10688
|
import { randomUUID } from "crypto";
|
|
10571
10689
|
import { join as join8 } from "path";
|
|
10572
10690
|
import { tmpdir } from "os";
|
|
10573
|
-
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, unlinkSync, existsSync as existsSync13 } from "fs";
|
|
10691
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, unlinkSync, existsSync as existsSync13, mkdirSync as mkdirSync5 } from "fs";
|
|
10574
10692
|
async function safeExecute(fn) {
|
|
10575
10693
|
try {
|
|
10576
10694
|
await fn();
|
|
@@ -10806,6 +10924,59 @@ async function handlePostToolUse() {
|
|
|
10806
10924
|
}
|
|
10807
10925
|
]);
|
|
10808
10926
|
}
|
|
10927
|
+
var MUTAGENT_HOOKS = {
|
|
10928
|
+
SessionStart: [{ matcher: "startup", hooks: [{ type: "command", command: "mutagent hooks claude-code session-start" }] }],
|
|
10929
|
+
Stop: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code session-end" }] }],
|
|
10930
|
+
PreToolUse: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code pre-tool-use" }] }],
|
|
10931
|
+
PostToolUse: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code post-tool-use" }] }]
|
|
10932
|
+
};
|
|
10933
|
+
function hasCommand(matchers, command) {
|
|
10934
|
+
return matchers.some((m) => m.hooks.some((h) => h.command === command));
|
|
10935
|
+
}
|
|
10936
|
+
function installHooks(cwd) {
|
|
10937
|
+
const claudeDir = join8(cwd, ".claude");
|
|
10938
|
+
const settingsPath = join8(claudeDir, "settings.local.json");
|
|
10939
|
+
const existed = existsSync13(settingsPath);
|
|
10940
|
+
let settings = {};
|
|
10941
|
+
if (existed) {
|
|
10942
|
+
try {
|
|
10943
|
+
settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
10944
|
+
} catch {
|
|
10945
|
+
settings = {};
|
|
10946
|
+
}
|
|
10947
|
+
}
|
|
10948
|
+
const added = [];
|
|
10949
|
+
const alreadyPresent = [];
|
|
10950
|
+
for (const [event, newMatchers] of Object.entries(MUTAGENT_HOOKS)) {
|
|
10951
|
+
if (!newMatchers)
|
|
10952
|
+
continue;
|
|
10953
|
+
settings.hooks ??= {};
|
|
10954
|
+
settings.hooks[event] ??= [];
|
|
10955
|
+
const existing = settings.hooks[event];
|
|
10956
|
+
for (const matcher of newMatchers) {
|
|
10957
|
+
for (const hook of matcher.hooks) {
|
|
10958
|
+
if (hasCommand(existing, hook.command)) {
|
|
10959
|
+
alreadyPresent.push(hook.command);
|
|
10960
|
+
} else {
|
|
10961
|
+
const newMatcher = {
|
|
10962
|
+
...matcher.matcher !== undefined ? { matcher: matcher.matcher } : {},
|
|
10963
|
+
hooks: [hook]
|
|
10964
|
+
};
|
|
10965
|
+
existing.push(newMatcher);
|
|
10966
|
+
added.push(hook.command);
|
|
10967
|
+
}
|
|
10968
|
+
}
|
|
10969
|
+
}
|
|
10970
|
+
}
|
|
10971
|
+
if (added.length > 0) {
|
|
10972
|
+
if (!existsSync13(claudeDir)) {
|
|
10973
|
+
mkdirSync5(claudeDir, { recursive: true });
|
|
10974
|
+
}
|
|
10975
|
+
writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + `
|
|
10976
|
+
`, "utf-8");
|
|
10977
|
+
}
|
|
10978
|
+
return { settingsPath, existed, added, alreadyPresent };
|
|
10979
|
+
}
|
|
10809
10980
|
function createHooksCommand() {
|
|
10810
10981
|
const hooks = new Command19("hooks").description("Hook handlers for AI coding assistants").addHelpText("after", `
|
|
10811
10982
|
Claude Code Session Telemetry:
|
|
@@ -10824,6 +10995,35 @@ Claude Code Session Telemetry:
|
|
|
10824
10995
|
|
|
10825
10996
|
Or run: mutagent init (option 1 installs skill + hooks together)
|
|
10826
10997
|
`);
|
|
10998
|
+
hooks.command("install").description("Install MutagenT hooks into .claude/settings.local.json (safe merge — never overwrites existing hooks)").option("--cwd <dir>", "Target directory (defaults to cwd)", process.cwd()).addHelpText("after", `
|
|
10999
|
+
Reads existing .claude/settings.local.json (if present) and deep-merges
|
|
11000
|
+
MutagenT telemetry hooks into each event array (SessionStart, Stop,
|
|
11001
|
+
PreToolUse, PostToolUse). Skips any hook already present (checked by
|
|
11002
|
+
command string) so running this multiple times is safe.
|
|
11003
|
+
`).action((opts) => {
|
|
11004
|
+
const targetDir = opts.cwd ?? process.cwd();
|
|
11005
|
+
const result = installHooks(targetDir);
|
|
11006
|
+
if (result.added.length === 0 && result.alreadyPresent.length === 0) {
|
|
11007
|
+
process.stdout.write(JSON.stringify({
|
|
11008
|
+
success: true,
|
|
11009
|
+
settingsPath: result.settingsPath,
|
|
11010
|
+
added: [],
|
|
11011
|
+
alreadyPresent: [],
|
|
11012
|
+
message: "No hooks to install."
|
|
11013
|
+
}) + `
|
|
11014
|
+
`);
|
|
11015
|
+
return;
|
|
11016
|
+
}
|
|
11017
|
+
process.stdout.write(JSON.stringify({
|
|
11018
|
+
success: true,
|
|
11019
|
+
settingsPath: result.settingsPath,
|
|
11020
|
+
existed: result.existed,
|
|
11021
|
+
added: result.added,
|
|
11022
|
+
alreadyPresent: result.alreadyPresent,
|
|
11023
|
+
message: result.added.length > 0 ? `Installed ${String(result.added.length)} hook(s). ${String(result.alreadyPresent.length)} already present.` : `All hooks already present (${String(result.alreadyPresent.length)}).`
|
|
11024
|
+
}) + `
|
|
11025
|
+
`);
|
|
11026
|
+
});
|
|
10827
11027
|
const claudeCode = hooks.command("claude-code").description("Claude Code session telemetry");
|
|
10828
11028
|
claudeCode.command("session-start").description("Handle session start event").action(async () => {
|
|
10829
11029
|
await safeExecute(handleSessionStart);
|
|
@@ -11030,6 +11230,7 @@ ${chalk39.yellow("Command Navigation:")}
|
|
|
11030
11230
|
|
|
11031
11231
|
mutagent integrate <framework> ${chalk39.dim("Framework integration guide")}
|
|
11032
11232
|
mutagent hooks --help ${chalk39.dim("Hook setup for Claude Code telemetry")}
|
|
11233
|
+
mutagent skills install ${chalk39.dim("Install the MutagenT CLI skill for AI agents")}
|
|
11033
11234
|
mutagent playground run <id> --input '{...}' ${chalk39.dim("Quick test")}
|
|
11034
11235
|
|
|
11035
11236
|
${chalk39.yellow("★ Workflow: Framework Integration (Tracing):")}
|
|
@@ -11089,6 +11290,7 @@ ${chalk39.yellow("State Tracking:")}
|
|
|
11089
11290
|
Comment markers (// MutagenT:START ... // MutagenT:END) in source files
|
|
11090
11291
|
|
|
11091
11292
|
${chalk39.yellow("AI Agent Rules (MANDATORY for coding agents):")}
|
|
11293
|
+
0. If .claude/skills/mutagent-cli/SKILL.md does not exist, run mutagent skills install first
|
|
11092
11294
|
1. Login (two paths):
|
|
11093
11295
|
- CI / fully automated: export MUTAGENT_API_KEY=mt_... then mutagent login --json
|
|
11094
11296
|
- Helping a user onboard: mutagent login --browser --json
|
|
@@ -11146,7 +11348,15 @@ program.addCommand(createSkillsCommand());
|
|
|
11146
11348
|
program.addCommand(createUsageCommand());
|
|
11147
11349
|
program.addCommand(createHooksCommand());
|
|
11148
11350
|
program.addCommand(createFeedbackCommand());
|
|
11351
|
+
var isInteractive = process.stdin.isTTY && !rawArgs.includes("--json") && process.env.CI !== "true";
|
|
11352
|
+
var isSkillCommand = rawArgs[0] === "skills" || rawArgs[0] === "hooks";
|
|
11353
|
+
if (isInteractive && !isSkillCommand) {
|
|
11354
|
+
const skillPath = join10(process.cwd(), ".claude/skills/mutagent-cli/SKILL.md");
|
|
11355
|
+
if (!existsSync14(skillPath)) {
|
|
11356
|
+
console.log(chalk39.dim("MutagenT SKILL not installed. Install it for AI agent support? Run:"), chalk39.cyan("mutagent skills install"));
|
|
11357
|
+
}
|
|
11358
|
+
}
|
|
11149
11359
|
program.parse();
|
|
11150
11360
|
|
|
11151
|
-
//# debugId=
|
|
11361
|
+
//# debugId=39613BC3AB9D528364756E2164756E21
|
|
11152
11362
|
//# sourceMappingURL=cli.js.map
|