@mutagent/cli 0.1.123 → 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 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: "high",
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: "medium",
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: "medium",
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
- "Then add this hooks config to .claude/settings.local.json:",
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", "node_modules,dist,.git,build,.next,__pycache__,venv,.venv").option("--markers-only", "Only find existing MutagenT markers").addHelpText("after", `
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 ?? "node_modules,dist,.git,build,.next,__pycache__,venv,.venv");
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 result = exploreCodebase(exploreOpts);
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
- surfaces: prompts[], agents[], datasets[], markers[]
9999
- show command output to user
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=4EA6EB9078B51CC264756E2164756E21
11361
+ //# debugId=39613BC3AB9D528364756E2164756E21
11152
11362
  //# sourceMappingURL=cli.js.map