@mutagent/cli 0.1.131 → 0.1.132

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
@@ -1243,8 +1243,8 @@ var init_sdk_client = __esm(() => {
1243
1243
  // src/bin/cli.ts
1244
1244
  import { Command as Command21 } from "commander";
1245
1245
  import chalk39 from "chalk";
1246
- import { readFileSync as readFileSync12, existsSync as existsSync14 } from "fs";
1247
- import { join as join10, dirname as dirname3 } from "path";
1246
+ import { readFileSync as readFileSync13, existsSync as existsSync15 } from "fs";
1247
+ import { join as join11, dirname as dirname3 } from "path";
1248
1248
  import { fileURLToPath as fileURLToPath2 } from "url";
1249
1249
 
1250
1250
  // src/commands/auth.ts
@@ -10684,28 +10684,16 @@ Examples:
10684
10684
  return usage;
10685
10685
  }
10686
10686
 
10687
- // src/commands/hooks.ts
10688
- init_config();
10687
+ // src/commands/hooks/index.ts
10689
10688
  import { Command as Command19 } from "commander";
10689
+
10690
+ // src/commands/hooks/handlers-core.ts
10690
10691
  import { randomUUID } from "crypto";
10692
+
10693
+ // src/commands/hooks/state.ts
10694
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, renameSync, unlinkSync, existsSync as existsSync13 } from "fs";
10691
10695
  import { join as join8 } from "path";
10692
10696
  import { tmpdir } from "os";
10693
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, unlinkSync, existsSync as existsSync13, mkdirSync as mkdirSync5 } from "fs";
10694
- async function safeExecute(fn) {
10695
- try {
10696
- await fn();
10697
- } catch (err) {
10698
- process.stderr.write(`[mutagent hooks] Warning: ${err instanceof Error ? err.message : String(err)}
10699
- `);
10700
- }
10701
- }
10702
- async function readStdin() {
10703
- const chunks = [];
10704
- for await (const chunk of process.stdin) {
10705
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
10706
- }
10707
- return JSON.parse(Buffer.concat(chunks).toString("utf-8"));
10708
- }
10709
10697
  function stateFilePath(sessionId) {
10710
10698
  return join8(tmpdir(), `mutagent-hook-${sessionId}.json`);
10711
10699
  }
@@ -10714,13 +10702,23 @@ function readState(sessionId) {
10714
10702
  if (!existsSync13(path))
10715
10703
  return null;
10716
10704
  try {
10717
- return JSON.parse(readFileSync10(path, "utf-8"));
10705
+ const raw = JSON.parse(readFileSync10(path, "utf-8"));
10706
+ if (!Array.isArray(raw.parentStack)) {
10707
+ raw.parentStack = [];
10708
+ }
10709
+ if (!Array.isArray(raw.parentStackKinds)) {
10710
+ raw.parentStackKinds = raw.parentStack.map(() => "agent");
10711
+ }
10712
+ return raw;
10718
10713
  } catch {
10719
10714
  return null;
10720
10715
  }
10721
10716
  }
10722
10717
  function writeState(sessionId, state) {
10723
- writeFileSync6(stateFilePath(sessionId), JSON.stringify(state), "utf-8");
10718
+ const path = stateFilePath(sessionId);
10719
+ const tmpPath = `${path}.${process.pid.toString()}.tmp`;
10720
+ writeFileSync6(tmpPath, JSON.stringify(state), "utf-8");
10721
+ renameSync(tmpPath, path);
10724
10722
  }
10725
10723
  function deleteState(sessionId) {
10726
10724
  const path = stateFilePath(sessionId);
@@ -10730,6 +10728,30 @@ function deleteState(sessionId) {
10730
10728
  } catch {}
10731
10729
  }
10732
10730
  }
10731
+ function pushParent(state, spanId, kind = "agent") {
10732
+ state.parentStack.push(spanId);
10733
+ state.parentStackKinds.push(kind);
10734
+ return state;
10735
+ }
10736
+ function popParent(state) {
10737
+ if (state.parentStack.length === 0)
10738
+ return null;
10739
+ state.parentStackKinds.pop();
10740
+ return state.parentStack.pop() ?? null;
10741
+ }
10742
+ function peekParent(state) {
10743
+ if (state.parentStack.length === 0)
10744
+ return null;
10745
+ return state.parentStack[state.parentStack.length - 1] ?? null;
10746
+ }
10747
+ function peekParentKind(state) {
10748
+ if (state.parentStackKinds.length === 0)
10749
+ return null;
10750
+ return state.parentStackKinds[state.parentStackKinds.length - 1] ?? null;
10751
+ }
10752
+
10753
+ // src/commands/hooks/api.ts
10754
+ init_config();
10733
10755
  var API_TIMEOUT_MS = 5000;
10734
10756
  async function sendBatchTrace(traces) {
10735
10757
  const apiKey = getApiKey();
@@ -10770,6 +10792,23 @@ async function sendBatchTrace(traces) {
10770
10792
  clearTimeout(timeout);
10771
10793
  }
10772
10794
  }
10795
+
10796
+ // src/commands/hooks/handlers-core.ts
10797
+ async function readStdin() {
10798
+ const chunks = [];
10799
+ for await (const chunk of process.stdin) {
10800
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
10801
+ }
10802
+ return JSON.parse(Buffer.concat(chunks).toString("utf-8"));
10803
+ }
10804
+ async function safeExecute(fn) {
10805
+ try {
10806
+ await fn();
10807
+ } catch (err) {
10808
+ process.stderr.write(`[mutagent hooks] Warning: ${err instanceof Error ? err.message : String(err)}
10809
+ `);
10810
+ }
10811
+ }
10773
10812
  function getString(input, ...keys) {
10774
10813
  for (const key of keys) {
10775
10814
  const val = input[key];
@@ -10790,12 +10829,16 @@ async function handleSessionStart() {
10790
10829
  throw new Error("Missing session_id in stdin");
10791
10830
  const now = new Date().toISOString();
10792
10831
  const traceId = `cc-${sessionId}`;
10832
+ const rootSpanId = randomUUID();
10793
10833
  const state = {
10794
10834
  traceId,
10795
10835
  sessionId,
10796
10836
  startTime: now,
10797
- openSpans: {}
10837
+ openSpans: {},
10838
+ parentStack: [],
10839
+ parentStackKinds: []
10798
10840
  };
10841
+ pushParent(state, rootSpanId, "agent");
10799
10842
  writeState(sessionId, state);
10800
10843
  await sendBatchTrace([
10801
10844
  {
@@ -10805,7 +10848,16 @@ async function handleSessionStart() {
10805
10848
  source: "sdk",
10806
10849
  startTime: now,
10807
10850
  status: "running",
10808
- spans: []
10851
+ spans: [
10852
+ {
10853
+ spanId: rootSpanId,
10854
+ name: "Claude Code Session",
10855
+ kind: "agent",
10856
+ startTime: now,
10857
+ status: "running",
10858
+ parentSpanId: null
10859
+ }
10860
+ ]
10809
10861
  }
10810
10862
  ]);
10811
10863
  }
@@ -10818,6 +10870,39 @@ async function handleSessionEnd() {
10818
10870
  const state = readState(sessionId);
10819
10871
  const traceId = state?.traceId ?? `cc-${sessionId}`;
10820
10872
  const startTime = state?.startTime ?? now;
10873
+ const spansToClose = [];
10874
+ if (state && state.parentStack.length > 0) {
10875
+ const stackCopy = [...state.parentStack];
10876
+ const kindsCopy = [...state.parentStackKinds];
10877
+ for (let i = stackCopy.length - 1;i > 0; i--) {
10878
+ const orphanId = stackCopy[i];
10879
+ const orphanKind = kindsCopy[i] ?? "agent";
10880
+ if (orphanId) {
10881
+ spansToClose.push({
10882
+ spanId: orphanId,
10883
+ name: "orphaned span",
10884
+ kind: orphanKind,
10885
+ startTime: now,
10886
+ endTime: now,
10887
+ status: "error",
10888
+ output: "orphaned at session end",
10889
+ parentSpanId: stackCopy[i - 1] ?? null
10890
+ });
10891
+ }
10892
+ }
10893
+ const rootSpanId = stackCopy[0];
10894
+ if (rootSpanId) {
10895
+ spansToClose.push({
10896
+ spanId: rootSpanId,
10897
+ name: "Claude Code Session",
10898
+ kind: "agent",
10899
+ startTime: state.startTime,
10900
+ endTime: now,
10901
+ status: "completed",
10902
+ parentSpanId: null
10903
+ });
10904
+ }
10905
+ }
10821
10906
  await sendBatchTrace([
10822
10907
  {
10823
10908
  traceId,
@@ -10827,7 +10912,7 @@ async function handleSessionEnd() {
10827
10912
  startTime,
10828
10913
  endTime: now,
10829
10914
  status: "completed",
10830
- spans: []
10915
+ spans: spansToClose
10831
10916
  }
10832
10917
  ]);
10833
10918
  deleteState(sessionId);
@@ -10843,8 +10928,11 @@ async function handlePreToolUse() {
10843
10928
  traceId: `cc-${sessionId}`,
10844
10929
  sessionId,
10845
10930
  startTime: now,
10846
- openSpans: {}
10931
+ openSpans: {},
10932
+ parentStack: [],
10933
+ parentStackKinds: []
10847
10934
  };
10935
+ const parentSpanId = peekParent(state);
10848
10936
  const spanId = randomUUID();
10849
10937
  state.openSpans[spanId] = {
10850
10938
  spanId,
@@ -10868,7 +10956,8 @@ async function handlePreToolUse() {
10868
10956
  kind: "tool",
10869
10957
  startTime: now,
10870
10958
  status: "running",
10871
- input: toolInput
10959
+ ...toolInput !== undefined ? { input: toolInput } : {},
10960
+ ...parentSpanId !== null ? { parentSpanId } : {}
10872
10961
  }
10873
10962
  ]
10874
10963
  }
@@ -10884,21 +10973,23 @@ async function handlePostToolUse() {
10884
10973
  const state = readState(sessionId);
10885
10974
  const traceId = state?.traceId ?? `cc-${sessionId}`;
10886
10975
  const startTime = state?.startTime ?? now;
10887
- let matchedSpan = null;
10976
+ let matchedSpanId = null;
10977
+ let matchedSpanStart = now;
10888
10978
  let matchedKey = null;
10889
10979
  if (state?.openSpans) {
10890
10980
  const entries = Object.entries(state.openSpans);
10891
10981
  for (let i = entries.length - 1;i >= 0; i--) {
10892
10982
  const entry = entries[i];
10893
10983
  if (entry && entry[1].toolName === toolName) {
10894
- matchedSpan = entry[1];
10984
+ matchedSpanId = entry[1].spanId;
10985
+ matchedSpanStart = entry[1].startTime;
10895
10986
  matchedKey = entry[0];
10896
10987
  break;
10897
10988
  }
10898
10989
  }
10899
10990
  }
10900
- const spanId = matchedSpan?.spanId ?? randomUUID();
10901
- const spanStartTime = matchedSpan?.startTime ?? now;
10991
+ const spanId = matchedSpanId ?? randomUUID();
10992
+ const spanStartTime = matchedSpanStart;
10902
10993
  if (state && matchedKey) {
10903
10994
  state.openSpans = Object.fromEntries(Object.entries(state.openSpans).filter(([k]) => k !== matchedKey));
10904
10995
  writeState(sessionId, state);
@@ -10920,29 +11011,365 @@ async function handlePostToolUse() {
10920
11011
  startTime: spanStartTime,
10921
11012
  endTime: now,
10922
11013
  status: "completed",
10923
- output: toolOutput
11014
+ ...toolOutput !== undefined ? { output: toolOutput } : {}
11015
+ }
11016
+ ]
11017
+ }
11018
+ ]);
11019
+ }
11020
+
11021
+ // src/commands/hooks/handlers-v2.ts
11022
+ import { randomUUID as randomUUID2 } from "crypto";
11023
+ async function handleUserPromptSubmit() {
11024
+ const input = await readStdin();
11025
+ const sessionId = getString(input, "session_id", "sessionId");
11026
+ if (!sessionId)
11027
+ throw new Error("Missing session_id in stdin");
11028
+ const now = new Date().toISOString();
11029
+ const state = readState(sessionId) ?? {
11030
+ traceId: `cc-${sessionId}`,
11031
+ sessionId,
11032
+ startTime: now,
11033
+ openSpans: {},
11034
+ parentStack: [],
11035
+ parentStackKinds: []
11036
+ };
11037
+ const parentSpanId = peekParent(state);
11038
+ const turnSpanId = randomUUID2();
11039
+ const prompt = input.prompt ?? input.message ?? input.text;
11040
+ const inputPayload = serializePayload(prompt ? { prompt } : undefined);
11041
+ pushParent(state, turnSpanId, "chain");
11042
+ writeState(sessionId, state);
11043
+ await sendBatchTrace([
11044
+ {
11045
+ traceId: state.traceId,
11046
+ sessionId,
11047
+ name: "Claude Code Session",
11048
+ source: "sdk",
11049
+ startTime: state.startTime,
11050
+ status: "running",
11051
+ spans: [
11052
+ {
11053
+ spanId: turnSpanId,
11054
+ name: "User turn",
11055
+ kind: "chain",
11056
+ startTime: now,
11057
+ status: "running",
11058
+ ...inputPayload !== undefined ? { input: inputPayload } : {},
11059
+ ...parentSpanId !== null ? { parentSpanId } : {}
11060
+ }
11061
+ ]
11062
+ }
11063
+ ]);
11064
+ }
11065
+ async function handleStop() {
11066
+ const input = await readStdin();
11067
+ const sessionId = getString(input, "session_id", "sessionId");
11068
+ if (!sessionId)
11069
+ throw new Error("Missing session_id in stdin");
11070
+ const now = new Date().toISOString();
11071
+ const state = readState(sessionId);
11072
+ if (!state)
11073
+ return;
11074
+ if (state.parentStack.length <= 1)
11075
+ return;
11076
+ const topKind = peekParentKind(state);
11077
+ if (topKind !== "chain") {
11078
+ process.stderr.write(`[mutagent hooks] Warning: Stop fired but stack top is kind="${topKind ?? "unknown"}" (expected "chain"). Skipping pop.
11079
+ `);
11080
+ return;
11081
+ }
11082
+ const turnSpanId = popParent(state);
11083
+ writeState(sessionId, state);
11084
+ if (!turnSpanId)
11085
+ return;
11086
+ await sendBatchTrace([
11087
+ {
11088
+ traceId: state.traceId,
11089
+ sessionId,
11090
+ name: "Claude Code Session",
11091
+ source: "sdk",
11092
+ startTime: state.startTime,
11093
+ status: "running",
11094
+ spans: [
11095
+ {
11096
+ spanId: turnSpanId,
11097
+ name: "User turn",
11098
+ kind: "chain",
11099
+ startTime: now,
11100
+ endTime: now,
11101
+ status: "completed",
11102
+ parentSpanId: peekParent(state)
11103
+ }
11104
+ ]
11105
+ }
11106
+ ]);
11107
+ }
11108
+ async function handleSubagentStart() {
11109
+ const input = await readStdin();
11110
+ const sessionId = getString(input, "session_id", "sessionId");
11111
+ if (!sessionId)
11112
+ throw new Error("Missing session_id in stdin");
11113
+ const now = new Date().toISOString();
11114
+ const state = readState(sessionId) ?? {
11115
+ traceId: `cc-${sessionId}`,
11116
+ sessionId,
11117
+ startTime: now,
11118
+ openSpans: {},
11119
+ parentStack: [],
11120
+ parentStackKinds: []
11121
+ };
11122
+ const parentSpanId = peekParent(state);
11123
+ const agentSpanId = randomUUID2();
11124
+ const agentType = getString(input, "agent_type", "agentType") || "subagent";
11125
+ const agentId = getString(input, "agent_id", "agentId");
11126
+ const agentName = agentId ? `${agentType}:${agentId}` : agentType;
11127
+ pushParent(state, agentSpanId, "agent");
11128
+ writeState(sessionId, state);
11129
+ await sendBatchTrace([
11130
+ {
11131
+ traceId: state.traceId,
11132
+ sessionId,
11133
+ name: "Claude Code Session",
11134
+ source: "sdk",
11135
+ startTime: state.startTime,
11136
+ status: "running",
11137
+ spans: [
11138
+ {
11139
+ spanId: agentSpanId,
11140
+ name: agentName,
11141
+ kind: "agent",
11142
+ startTime: now,
11143
+ status: "running",
11144
+ ...parentSpanId !== null ? { parentSpanId } : {}
11145
+ }
11146
+ ]
11147
+ }
11148
+ ]);
11149
+ }
11150
+ async function handleSubagentStop() {
11151
+ const input = await readStdin();
11152
+ const sessionId = getString(input, "session_id", "sessionId");
11153
+ if (!sessionId)
11154
+ throw new Error("Missing session_id in stdin");
11155
+ const now = new Date().toISOString();
11156
+ const state = readState(sessionId);
11157
+ if (!state) {
11158
+ process.stderr.write(`[mutagent hooks] Warning: SubagentStop received but no state found for session ${sessionId}
11159
+ `);
11160
+ return;
11161
+ }
11162
+ if (state.parentStack.length <= 1) {
11163
+ process.stderr.write(`[mutagent hooks] Warning: SubagentStop with no matching SubagentStart in session ${sessionId}
11164
+ `);
11165
+ return;
11166
+ }
11167
+ const topKind = peekParentKind(state);
11168
+ if (topKind !== "agent") {
11169
+ process.stderr.write(`[mutagent hooks] Warning: SubagentStop but stack top is kind="${topKind ?? "unknown"}" (expected "agent"). Skipping pop.
11170
+ `);
11171
+ return;
11172
+ }
11173
+ const agentSpanId = popParent(state);
11174
+ const newParent = peekParent(state);
11175
+ writeState(sessionId, state);
11176
+ if (!agentSpanId)
11177
+ return;
11178
+ await sendBatchTrace([
11179
+ {
11180
+ traceId: state.traceId,
11181
+ sessionId,
11182
+ name: "Claude Code Session",
11183
+ source: "sdk",
11184
+ startTime: state.startTime,
11185
+ status: "running",
11186
+ spans: [
11187
+ {
11188
+ spanId: agentSpanId,
11189
+ name: "subagent",
11190
+ kind: "agent",
11191
+ startTime: now,
11192
+ endTime: now,
11193
+ status: "completed",
11194
+ ...newParent !== null ? { parentSpanId: newParent } : {}
11195
+ }
11196
+ ]
11197
+ }
11198
+ ]);
11199
+ }
11200
+ async function handlePreCompact() {
11201
+ const input = await readStdin();
11202
+ const sessionId = getString(input, "session_id", "sessionId");
11203
+ if (!sessionId)
11204
+ throw new Error("Missing session_id in stdin");
11205
+ const now = new Date().toISOString();
11206
+ const state = readState(sessionId) ?? {
11207
+ traceId: `cc-${sessionId}`,
11208
+ sessionId,
11209
+ startTime: now,
11210
+ openSpans: {},
11211
+ parentStack: [],
11212
+ parentStackKinds: []
11213
+ };
11214
+ const parentSpanId = peekParent(state);
11215
+ const compactSpanId = randomUUID2();
11216
+ pushParent(state, compactSpanId, "custom");
11217
+ writeState(sessionId, state);
11218
+ await sendBatchTrace([
11219
+ {
11220
+ traceId: state.traceId,
11221
+ sessionId,
11222
+ name: "Claude Code Session",
11223
+ source: "sdk",
11224
+ startTime: state.startTime,
11225
+ status: "running",
11226
+ spans: [
11227
+ {
11228
+ spanId: compactSpanId,
11229
+ name: "Compaction",
11230
+ kind: "custom",
11231
+ startTime: now,
11232
+ status: "running",
11233
+ ...parentSpanId !== null ? { parentSpanId } : {}
11234
+ }
11235
+ ]
11236
+ }
11237
+ ]);
11238
+ }
11239
+ async function handlePostCompact() {
11240
+ const input = await readStdin();
11241
+ const sessionId = getString(input, "session_id", "sessionId");
11242
+ if (!sessionId)
11243
+ throw new Error("Missing session_id in stdin");
11244
+ const now = new Date().toISOString();
11245
+ const state = readState(sessionId);
11246
+ if (!state) {
11247
+ process.stderr.write(`[mutagent hooks] Warning: PostCompact received but no state found for session ${sessionId}
11248
+ `);
11249
+ return;
11250
+ }
11251
+ if (state.parentStack.length <= 1) {
11252
+ process.stderr.write(`[mutagent hooks] Warning: PostCompact with no matching PreCompact in session ${sessionId}
11253
+ `);
11254
+ return;
11255
+ }
11256
+ const compactSpanId = popParent(state);
11257
+ const newParent = peekParent(state);
11258
+ writeState(sessionId, state);
11259
+ if (!compactSpanId)
11260
+ return;
11261
+ const summary = input.summary ?? input.compaction_summary ?? input.compactionSummary;
11262
+ const outputPayload = serializePayload(summary ?? "Context compacted");
11263
+ await sendBatchTrace([
11264
+ {
11265
+ traceId: state.traceId,
11266
+ sessionId,
11267
+ name: "Claude Code Session",
11268
+ source: "sdk",
11269
+ startTime: state.startTime,
11270
+ status: "running",
11271
+ spans: [
11272
+ {
11273
+ spanId: compactSpanId,
11274
+ name: "Compaction",
11275
+ kind: "custom",
11276
+ startTime: now,
11277
+ endTime: now,
11278
+ status: "completed",
11279
+ ...outputPayload !== undefined ? { output: outputPayload } : {},
11280
+ ...newParent !== null ? { parentSpanId: newParent } : {}
10924
11281
  }
10925
11282
  ]
10926
11283
  }
10927
11284
  ]);
10928
11285
  }
11286
+ async function handlePostToolUseFailure() {
11287
+ const input = await readStdin();
11288
+ const sessionId = getString(input, "session_id", "sessionId");
11289
+ const toolName = getString(input, "tool_name", "toolName") || "unknown";
11290
+ if (!sessionId)
11291
+ throw new Error("Missing session_id in stdin");
11292
+ const now = new Date().toISOString();
11293
+ const state = readState(sessionId);
11294
+ if (!state) {
11295
+ process.stderr.write(`[mutagent hooks] Warning: PostToolUseFailure received but no state found for session ${sessionId}
11296
+ `);
11297
+ return;
11298
+ }
11299
+ const traceId = state.traceId;
11300
+ const startTime = state.startTime;
11301
+ let matchedSpanId = null;
11302
+ let matchedSpanStart = now;
11303
+ let matchedKey = null;
11304
+ const entries = Object.entries(state.openSpans);
11305
+ for (let i = entries.length - 1;i >= 0; i--) {
11306
+ const entry = entries[i];
11307
+ if (entry && entry[1].toolName === toolName) {
11308
+ matchedSpanId = entry[1].spanId;
11309
+ matchedSpanStart = entry[1].startTime;
11310
+ matchedKey = entry[0];
11311
+ break;
11312
+ }
11313
+ }
11314
+ if (!matchedSpanId) {
11315
+ process.stderr.write(`[mutagent hooks] Warning: PostToolUseFailure — no matching open span for tool "${toolName}"
11316
+ `);
11317
+ return;
11318
+ }
11319
+ state.openSpans = Object.fromEntries(Object.entries(state.openSpans).filter(([k]) => k !== matchedKey));
11320
+ writeState(sessionId, state);
11321
+ const reason = getString(input, "error", "reason", "message") || "Tool use failed";
11322
+ const errorPayload = serializePayload(reason);
11323
+ await sendBatchTrace([
11324
+ {
11325
+ traceId,
11326
+ sessionId,
11327
+ name: "Claude Code Session",
11328
+ source: "sdk",
11329
+ startTime,
11330
+ status: "running",
11331
+ spans: [
11332
+ {
11333
+ spanId: matchedSpanId,
11334
+ name: toolName,
11335
+ kind: "tool",
11336
+ startTime: matchedSpanStart,
11337
+ endTime: now,
11338
+ status: "error",
11339
+ ...errorPayload !== undefined ? { output: errorPayload } : {}
11340
+ }
11341
+ ]
11342
+ }
11343
+ ]);
11344
+ }
11345
+
11346
+ // src/commands/hooks/install.ts
11347
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, existsSync as existsSync14, mkdirSync as mkdirSync5 } from "fs";
11348
+ import { join as join9 } from "path";
10929
11349
  var MUTAGENT_HOOKS = {
10930
11350
  SessionStart: [{ matcher: "startup", hooks: [{ type: "command", command: "mutagent hooks claude-code session-start" }] }],
10931
- Stop: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code session-end" }] }],
10932
11351
  PreToolUse: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code pre-tool-use" }] }],
10933
- PostToolUse: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code post-tool-use" }] }]
11352
+ PostToolUse: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code post-tool-use" }] }],
11353
+ Stop: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code stop" }] }],
11354
+ SessionEnd: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code session-end" }] }],
11355
+ UserPromptSubmit: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code user-prompt-submit" }] }],
11356
+ SubagentStart: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code subagent-start" }] }],
11357
+ SubagentStop: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code subagent-stop" }] }],
11358
+ PreCompact: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code pre-compact" }] }],
11359
+ PostCompact: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code post-compact" }] }],
11360
+ PostToolUseFailure: [{ hooks: [{ type: "command", command: "mutagent hooks claude-code post-tool-use-failure" }] }]
10934
11361
  };
10935
11362
  function hasCommand(matchers, command) {
10936
11363
  return matchers.some((m) => m.hooks.some((h) => h.command === command));
10937
11364
  }
10938
11365
  function installHooks(cwd) {
10939
- const claudeDir = join8(cwd, ".claude");
10940
- const settingsPath = join8(claudeDir, "settings.local.json");
10941
- const existed = existsSync13(settingsPath);
11366
+ const claudeDir = join9(cwd, ".claude");
11367
+ const settingsPath = join9(claudeDir, "settings.local.json");
11368
+ const existed = existsSync14(settingsPath);
10942
11369
  let settings = {};
10943
11370
  if (existed) {
10944
11371
  try {
10945
- settings = JSON.parse(readFileSync10(settingsPath, "utf-8"));
11372
+ settings = JSON.parse(readFileSync11(settingsPath, "utf-8"));
10946
11373
  } catch {
10947
11374
  settings = {};
10948
11375
  }
@@ -10971,14 +11398,16 @@ function installHooks(cwd) {
10971
11398
  }
10972
11399
  }
10973
11400
  if (added.length > 0) {
10974
- if (!existsSync13(claudeDir)) {
11401
+ if (!existsSync14(claudeDir)) {
10975
11402
  mkdirSync5(claudeDir, { recursive: true });
10976
11403
  }
10977
- writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + `
11404
+ writeFileSync7(settingsPath, JSON.stringify(settings, null, 2) + `
10978
11405
  `, "utf-8");
10979
11406
  }
10980
11407
  return { settingsPath, existed, added, alreadyPresent };
10981
11408
  }
11409
+
11410
+ // src/commands/hooks/index.ts
10982
11411
  function createHooksCommand() {
10983
11412
  const hooks = new Command19("hooks").description("Hook handlers for AI coding assistants").addHelpText("after", `
10984
11413
  Claude Code Session Telemetry:
@@ -10991,17 +11420,23 @@ Claude Code Session Telemetry:
10991
11420
  "SessionStart": [{"matcher": "startup", "hooks": [{"type": "command", "command": "mutagent hooks claude-code session-start"}]}],
10992
11421
  "Stop": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code session-end"}]}],
10993
11422
  "PreToolUse": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code pre-tool-use"}]}],
10994
- "PostToolUse": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code post-tool-use"}]}]
11423
+ "PostToolUse": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code post-tool-use"}]}],
11424
+ "UserPromptSubmit": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code user-prompt-submit"}]}],
11425
+ "SubagentStart": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code subagent-start"}]}],
11426
+ "SubagentStop": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code subagent-stop"}]}],
11427
+ "PreCompact": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code pre-compact"}]}],
11428
+ "PostCompact": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code post-compact"}]}],
11429
+ "PostToolUseFailure": [{"hooks": [{"type": "command", "command": "mutagent hooks claude-code post-tool-use-failure"}]}]
10995
11430
  }
10996
11431
  }
10997
11432
 
10998
- Or run: mutagent init (option 1 installs skill + hooks together)
11433
+ Or run: mutagent hooks install
10999
11434
  `);
11000
11435
  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", `
11001
11436
  Reads existing .claude/settings.local.json (if present) and deep-merges
11002
- MutagenT telemetry hooks into each event array (SessionStart, Stop,
11003
- PreToolUse, PostToolUse). Skips any hook already present (checked by
11004
- command string) so running this multiple times is safe.
11437
+ MutagenT telemetry hooks into each event array (all 10 events). Skips any
11438
+ hook already present (checked by command string) so running this multiple
11439
+ times is safe.
11005
11440
  `).action((opts) => {
11006
11441
  const targetDir = opts.cwd ?? process.cwd();
11007
11442
  const result = installHooks(targetDir);
@@ -11039,6 +11474,27 @@ command string) so running this multiple times is safe.
11039
11474
  claudeCode.command("post-tool-use").description("Handle post-tool-use event").action(async () => {
11040
11475
  await safeExecute(handlePostToolUse);
11041
11476
  });
11477
+ claudeCode.command("user-prompt-submit").description("Handle user prompt submit event (creates turn span)").action(async () => {
11478
+ await safeExecute(handleUserPromptSubmit);
11479
+ });
11480
+ claudeCode.command("stop").description("Handle stop event (closes current turn span)").action(async () => {
11481
+ await safeExecute(handleStop);
11482
+ });
11483
+ claudeCode.command("subagent-start").description("Handle subagent start event (creates nested agent span)").action(async () => {
11484
+ await safeExecute(handleSubagentStart);
11485
+ });
11486
+ claudeCode.command("subagent-stop").description("Handle subagent stop event (closes subagent span)").action(async () => {
11487
+ await safeExecute(handleSubagentStop);
11488
+ });
11489
+ claudeCode.command("pre-compact").description("Handle pre-compact event (opens compaction span)").action(async () => {
11490
+ await safeExecute(handlePreCompact);
11491
+ });
11492
+ claudeCode.command("post-compact").description("Handle post-compact event (closes compaction span with summary)").action(async () => {
11493
+ await safeExecute(handlePostCompact);
11494
+ });
11495
+ claudeCode.command("post-tool-use-failure").description("Handle post-tool-use-failure event (closes failed span with error status)").action(async () => {
11496
+ await safeExecute(handlePostToolUseFailure);
11497
+ });
11042
11498
  return hooks;
11043
11499
  }
11044
11500
 
@@ -11047,8 +11503,8 @@ import { Command as Command20 } from "commander";
11047
11503
  import chalk38 from "chalk";
11048
11504
  init_errors();
11049
11505
  init_config();
11050
- import { readFileSync as readFileSync11 } from "fs";
11051
- import { join as join9, dirname as dirname2 } from "path";
11506
+ import { readFileSync as readFileSync12 } from "fs";
11507
+ import { join as join10, dirname as dirname2 } from "path";
11052
11508
  import { fileURLToPath } from "url";
11053
11509
  var VALID_CATEGORIES = ["bug", "feature", "improvement", "praise"];
11054
11510
  function getCliVersion() {
@@ -11057,8 +11513,8 @@ function getCliVersion() {
11057
11513
  }
11058
11514
  try {
11059
11515
  const __dirname2 = dirname2(fileURLToPath(import.meta.url));
11060
- const pkgPath = join9(__dirname2, "..", "..", "package.json");
11061
- const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
11516
+ const pkgPath = join10(__dirname2, "..", "..", "package.json");
11517
+ const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
11062
11518
  return pkg.version ?? "0.1.1";
11063
11519
  } catch {
11064
11520
  return "0.1.1";
@@ -11183,8 +11639,8 @@ if (process.env.CLI_VERSION) {
11183
11639
  } else {
11184
11640
  try {
11185
11641
  const __dirname2 = dirname3(fileURLToPath2(import.meta.url));
11186
- const pkgPath = join10(__dirname2, "..", "..", "package.json");
11187
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
11642
+ const pkgPath = join11(__dirname2, "..", "..", "package.json");
11643
+ const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
11188
11644
  cliVersion = pkg.version ?? cliVersion;
11189
11645
  } catch {}
11190
11646
  }
@@ -11353,12 +11809,12 @@ program.addCommand(createFeedbackCommand());
11353
11809
  var isInteractive = process.stdin.isTTY && !rawArgs.includes("--json") && process.env.CI !== "true";
11354
11810
  var isSkillCommand = rawArgs[0] === "skills" || rawArgs[0] === "hooks";
11355
11811
  if (isInteractive && !isSkillCommand) {
11356
- const skillPath = join10(process.cwd(), ".claude/skills/mutagent-cli/SKILL.md");
11357
- if (!existsSync14(skillPath)) {
11812
+ const skillPath = join11(process.cwd(), ".claude/skills/mutagent-cli/SKILL.md");
11813
+ if (!existsSync15(skillPath)) {
11358
11814
  console.log(chalk39.dim("MutagenT SKILL not installed. Install it for AI agent support? Run:"), chalk39.cyan("mutagent skills install"));
11359
11815
  }
11360
11816
  }
11361
11817
  program.parse();
11362
11818
 
11363
- //# debugId=A0F1B767D1BF2A2364756E2164756E21
11819
+ //# debugId=599B825650E0CCDF64756E2164756E21
11364
11820
  //# sourceMappingURL=cli.js.map