@wrongstack/plugins 0.303.0 → 0.305.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.
package/dist/index.js CHANGED
@@ -13131,13 +13131,11 @@ var plugin37 = {
13131
13131
  var notify_hub_default = plugin37;
13132
13132
 
13133
13133
  // src/path-guard/index.ts
13134
- var state35 = {
13135
- invocations: 0,
13136
- blocks: 0,
13137
- warns: 0,
13138
- lastBlock: null,
13139
- hookUnregister: null
13140
- };
13134
+ function createState() {
13135
+ return { invocations: 0, blocks: 0, warns: 0, lastBlock: null, hookUnregister: null };
13136
+ }
13137
+ var states = /* @__PURE__ */ new WeakMap();
13138
+ var latestState = createState();
13141
13139
  var DEFAULT_PROTECT = [
13142
13140
  "pnpm-lock.yaml",
13143
13141
  "package-lock.json",
@@ -14405,17 +14403,16 @@ var plugin38 = {
14405
14403
  }
14406
14404
  },
14407
14405
  setup(api) {
14408
- state35.invocations = 0;
14409
- state35.blocks = 0;
14410
- state35.warns = 0;
14411
- state35.lastBlock = null;
14412
- if (state35.hookUnregister) {
14406
+ const previous = states.get(api);
14407
+ if (previous?.hookUnregister) {
14413
14408
  try {
14414
- state35.hookUnregister();
14409
+ previous.hookUnregister();
14415
14410
  } catch {
14416
14411
  }
14417
- state35.hookUnregister = null;
14418
14412
  }
14413
+ const state59 = createState();
14414
+ states.set(api, state59);
14415
+ latestState = state59;
14419
14416
  const cfg = readConfig33(api.config.extensions?.["path-guard"]);
14420
14417
  const protectRes = cfg.protect.map(compilePathGlob);
14421
14418
  const allowRes = cfg.allow.map(compilePathGlob);
@@ -14423,15 +14420,15 @@ var plugin38 = {
14423
14420
  const subject = isScope ? `write scope "${path}" may include a protected path \u2014 narrow it or add an \`allow\` glob` : `"${path}" is a protected path`;
14424
14421
  const matchContext = isScope ? 'its unresolved scope overlaps config.extensions["path-guard"].protect' : 'matched by config.extensions["path-guard"].protect';
14425
14422
  if (cfg.mode === "block") {
14426
- state35.blocks += 1;
14427
- state35.lastBlock = { path, tool, when: (/* @__PURE__ */ new Date()).toISOString() };
14423
+ state59.blocks += 1;
14424
+ state59.lastBlock = { path, tool, when: (/* @__PURE__ */ new Date()).toISOString() };
14428
14425
  api.metrics.counter("blocks");
14429
14426
  return {
14430
14427
  decision: "block",
14431
14428
  reason: `path-guard: ${subject} (${matchContext}) \u2014 ${operation} refused. If this change is intentional, ask the user to do it, add an \`allow\` glob, or set mode: "warn".`
14432
14429
  };
14433
14430
  }
14434
- state35.warns += 1;
14431
+ state59.warns += 1;
14435
14432
  api.metrics.counter("warns");
14436
14433
  return {
14437
14434
  decision: "allow",
@@ -14440,7 +14437,7 @@ var plugin38 = {
14440
14437
  };
14441
14438
  const hook = (input) => {
14442
14439
  if (!cfg.enabled) return;
14443
- state35.invocations += 1;
14440
+ state59.invocations += 1;
14444
14441
  const toolName = input.toolName ?? "";
14445
14442
  const ti = input.toolInput ?? {};
14446
14443
  const command = typeof ti["command"] === "string" ? ti["command"] : "";
@@ -14492,7 +14489,7 @@ var plugin38 = {
14492
14489
  }
14493
14490
  return;
14494
14491
  };
14495
- state35.hookUnregister = api.registerHook("PreToolUse", "*", hook, {
14492
+ state59.hookUnregister = api.registerHook("PreToolUse", "*", hook, {
14496
14493
  name: "path-guard",
14497
14494
  stage: "validate",
14498
14495
  failurePolicy: "closed",
@@ -14513,11 +14510,11 @@ var plugin38 = {
14513
14510
  protect: cfg.protect,
14514
14511
  allow: cfg.allow,
14515
14512
  counters: {
14516
- invocations: state35.invocations,
14517
- blocks: state35.blocks,
14518
- warns: state35.warns
14513
+ invocations: state59.invocations,
14514
+ blocks: state59.blocks,
14515
+ warns: state59.warns
14519
14516
  },
14520
- lastBlock: state35.lastBlock
14517
+ lastBlock: state59.lastBlock
14521
14518
  };
14522
14519
  }
14523
14520
  });
@@ -14529,28 +14526,32 @@ var plugin38 = {
14529
14526
  });
14530
14527
  },
14531
14528
  teardown(api) {
14532
- if (state35.hookUnregister) {
14529
+ const state59 = states.get(api);
14530
+ if (!state59) return;
14531
+ if (state59.hookUnregister) {
14533
14532
  try {
14534
- state35.hookUnregister();
14533
+ state59.hookUnregister();
14535
14534
  } catch {
14536
14535
  }
14537
- state35.hookUnregister = null;
14536
+ state59.hookUnregister = null;
14538
14537
  }
14539
- const final = { invocations: state35.invocations, blocks: state35.blocks, warns: state35.warns };
14540
- state35.invocations = 0;
14541
- state35.blocks = 0;
14542
- state35.warns = 0;
14543
- state35.lastBlock = null;
14538
+ const final = { invocations: state59.invocations, blocks: state59.blocks, warns: state59.warns };
14539
+ state59.invocations = 0;
14540
+ state59.blocks = 0;
14541
+ state59.warns = 0;
14542
+ state59.lastBlock = null;
14543
+ states.delete(api);
14544
14544
  api.log.info("path-guard: teardown complete", { final });
14545
14545
  },
14546
14546
  async health() {
14547
+ const state59 = latestState;
14547
14548
  return {
14548
14549
  ok: true,
14549
- message: state35.lastBlock === null ? `path-guard: ${state35.invocations} invocation(s), ${state35.blocks} block(s), ${state35.warns} warn(s)` : `path-guard: last block on "${state35.lastBlock.path}" (${state35.lastBlock.tool}) at ${state35.lastBlock.when}`,
14550
+ message: state59.lastBlock === null ? `path-guard: ${state59.invocations} invocation(s), ${state59.blocks} block(s), ${state59.warns} warn(s)` : `path-guard: last block on "${state59.lastBlock.path}" (${state59.lastBlock.tool}) at ${state59.lastBlock.when}`,
14550
14551
  counters: {
14551
- invocations: state35.invocations,
14552
- blocks: state35.blocks,
14553
- warns: state35.warns
14552
+ invocations: state59.invocations,
14553
+ blocks: state59.blocks,
14554
+ warns: state59.warns
14554
14555
  }
14555
14556
  };
14556
14557
  }
@@ -14561,7 +14562,7 @@ var path_guard_default = plugin38;
14561
14562
  import { existsSync as existsSync5, readFileSync as readFileSync11 } from "node:fs";
14562
14563
  import { isAbsolute as isAbsolute18, relative as relative18, resolve as resolve18 } from "node:path";
14563
14564
  var API_VERSION25 = "^0.1.10";
14564
- var state36 = {
14565
+ var state35 = {
14565
14566
  invocationCount: 0,
14566
14567
  comparisonCount: 0,
14567
14568
  regressionCount: 0,
@@ -14721,12 +14722,12 @@ var plugin39 = {
14721
14722
  }
14722
14723
  },
14723
14724
  setup(api) {
14724
- state36.invocationCount = 0;
14725
- state36.comparisonCount = 0;
14726
- state36.regressionCount = 0;
14727
- state36.missingResultsCount = 0;
14728
- state36.errorCount = 0;
14729
- state36.lastResult = null;
14725
+ state35.invocationCount = 0;
14726
+ state35.comparisonCount = 0;
14727
+ state35.regressionCount = 0;
14728
+ state35.missingResultsCount = 0;
14729
+ state35.errorCount = 0;
14730
+ state35.lastResult = null;
14730
14731
  const cfg = readConfig34(api.config.extensions?.["performance-regression-gate"]);
14731
14732
  api.tools.register({
14732
14733
  name: "perf_regression_status",
@@ -14756,16 +14757,16 @@ var plugin39 = {
14756
14757
  if (!cfg.enabled) {
14757
14758
  return { ok: false, error: "performance-regression-gate is disabled" };
14758
14759
  }
14759
- state36.invocationCount += 1;
14760
+ state35.invocationCount += 1;
14760
14761
  const threshold = typeof input.thresholdPercent === "number" && input.thresholdPercent >= 0 && input.thresholdPercent <= 1e3 ? input.thresholdPercent : cfg.thresholdPercent;
14761
14762
  const resultsPath = resolveProjectPath6(input.resultsPath || "bench-results.json") ?? "";
14762
14763
  if (!resultsPath) {
14763
- state36.errorCount += 1;
14764
+ state35.errorCount += 1;
14764
14765
  return { ok: false, error: "invalid results path (must be inside project)" };
14765
14766
  }
14766
14767
  const results = loadResults(resultsPath);
14767
14768
  if (!results) {
14768
- state36.missingResultsCount += 1;
14769
+ state35.missingResultsCount += 1;
14769
14770
  return {
14770
14771
  ok: true,
14771
14772
  hasResults: false,
@@ -14777,7 +14778,7 @@ var plugin39 = {
14777
14778
  }
14778
14779
  const current = flattenResults(results);
14779
14780
  if (current.length === 0) {
14780
- state36.missingResultsCount += 1;
14781
+ state35.missingResultsCount += 1;
14781
14782
  return {
14782
14783
  ok: true,
14783
14784
  hasResults: false,
@@ -14791,12 +14792,12 @@ var plugin39 = {
14791
14792
  if (input.baselinePath) {
14792
14793
  const baselineResolved = resolveProjectPath6(input.baselinePath) ?? "";
14793
14794
  if (!baselineResolved) {
14794
- state36.errorCount += 1;
14795
+ state35.errorCount += 1;
14795
14796
  return { ok: false, error: "invalid baseline path (must be inside project)" };
14796
14797
  }
14797
14798
  const baselineResults = loadResults(baselineResolved);
14798
14799
  if (!baselineResults) {
14799
- state36.errorCount += 1;
14800
+ state35.errorCount += 1;
14800
14801
  return {
14801
14802
  ok: false,
14802
14803
  error: `Could not read baseline results at ${input.baselinePath}.`
@@ -14808,9 +14809,9 @@ var plugin39 = {
14808
14809
  pairs = pairInternal(current);
14809
14810
  }
14810
14811
  const regressions = comparePairs(pairs, threshold);
14811
- state36.comparisonCount += pairs.length;
14812
- state36.regressionCount += regressions.length;
14813
- state36.lastResult = {
14812
+ state35.comparisonCount += pairs.length;
14813
+ state35.regressionCount += regressions.length;
14814
+ state35.lastResult = {
14814
14815
  comparisons: pairs.length,
14815
14816
  regressions: regressions.length,
14816
14817
  thresholdPercent: threshold,
@@ -14839,53 +14840,53 @@ var plugin39 = {
14839
14840
  },
14840
14841
  teardown(api) {
14841
14842
  const final = {
14842
- invocations: state36.invocationCount,
14843
- comparisons: state36.comparisonCount,
14844
- regressions: state36.regressionCount,
14845
- missingResults: state36.missingResultsCount,
14846
- errors: state36.errorCount
14843
+ invocations: state35.invocationCount,
14844
+ comparisons: state35.comparisonCount,
14845
+ regressions: state35.regressionCount,
14846
+ missingResults: state35.missingResultsCount,
14847
+ errors: state35.errorCount
14847
14848
  };
14848
- state36.invocationCount = 0;
14849
- state36.comparisonCount = 0;
14850
- state36.regressionCount = 0;
14851
- state36.missingResultsCount = 0;
14852
- state36.errorCount = 0;
14853
- state36.lastResult = null;
14849
+ state35.invocationCount = 0;
14850
+ state35.comparisonCount = 0;
14851
+ state35.regressionCount = 0;
14852
+ state35.missingResultsCount = 0;
14853
+ state35.errorCount = 0;
14854
+ state35.lastResult = null;
14854
14855
  api.log.info("performance-regression-gate: teardown complete", { final });
14855
14856
  },
14856
14857
  async health() {
14857
14858
  return {
14858
- ok: state36.errorCount === 0,
14859
- message: state36.lastResult ? `performance-regression-gate: ${state36.lastResult.regressions} regression(s) across ${state36.lastResult.comparisons} comparison(s) (threshold ${state36.lastResult.thresholdPercent}%)` : `performance-regression-gate: ${state36.invocationCount} invocation(s), ${state36.comparisonCount} comparison(s)`,
14859
+ ok: state35.errorCount === 0,
14860
+ message: state35.lastResult ? `performance-regression-gate: ${state35.lastResult.regressions} regression(s) across ${state35.lastResult.comparisons} comparison(s) (threshold ${state35.lastResult.thresholdPercent}%)` : `performance-regression-gate: ${state35.invocationCount} invocation(s), ${state35.comparisonCount} comparison(s)`,
14860
14861
  counters: {
14861
- invocations: state36.invocationCount,
14862
- comparisons: state36.comparisonCount,
14863
- regressions: state36.regressionCount,
14864
- missingResults: state36.missingResultsCount,
14865
- errors: state36.errorCount
14862
+ invocations: state35.invocationCount,
14863
+ comparisons: state35.comparisonCount,
14864
+ regressions: state35.regressionCount,
14865
+ missingResults: state35.missingResultsCount,
14866
+ errors: state35.errorCount
14866
14867
  },
14867
- lastResult: state36.lastResult
14868
+ lastResult: state35.lastResult
14868
14869
  };
14869
14870
  }
14870
14871
  };
14871
14872
  var performance_regression_gate_default = plugin39;
14872
14873
 
14873
14874
  // src/plugin-stack-observer/index.ts
14874
- var state37 = {
14875
+ var state36 = {
14875
14876
  wraps: [],
14876
14877
  contributions: 0,
14877
14878
  patternUnregister: null
14878
14879
  };
14879
14880
  function clearObserverState() {
14880
- if (state37.patternUnregister) {
14881
+ if (state36.patternUnregister) {
14881
14882
  try {
14882
- state37.patternUnregister();
14883
+ state36.patternUnregister();
14883
14884
  } catch {
14884
14885
  }
14885
- state37.patternUnregister = null;
14886
+ state36.patternUnregister = null;
14886
14887
  }
14887
- state37.wraps = [];
14888
- state37.contributions = 0;
14888
+ state36.wraps = [];
14889
+ state36.contributions = 0;
14889
14890
  }
14890
14891
  var PLUGIN = {
14891
14892
  name: "plugin-stack-observer",
@@ -14920,14 +14921,14 @@ var PLUGIN = {
14920
14921
  api.log.info("plugin-stack-observer loaded (disabled)");
14921
14922
  return;
14922
14923
  }
14923
- state37.patternUnregister = api.onPattern(
14924
+ state36.patternUnregister = api.onPattern(
14924
14925
  "provider.wrap:loaded",
14925
14926
  (_eventName, payload) => {
14926
14927
  const p = payload ?? {};
14927
14928
  if (typeof p.plugin !== "string" || p.plugin.length === 0) return;
14928
14929
  const wraps = Array.isArray(p.wraps) ? p.wraps.filter((w) => typeof w === "string") : [];
14929
14930
  const kind = typeof p.kind === "string" ? p.kind : "unknown";
14930
- state37.wraps.push({
14931
+ state36.wraps.push({
14931
14932
  plugin: p.plugin,
14932
14933
  kind,
14933
14934
  wraps,
@@ -14938,10 +14939,10 @@ var PLUGIN = {
14938
14939
  );
14939
14940
  if (cfg.injectIntoSystemPrompt) {
14940
14941
  api.registerSystemPromptContributor(async () => {
14941
- if (state37.wraps.length === 0) return [];
14942
- state37.contributions += 1;
14942
+ if (state36.wraps.length === 0) return [];
14943
+ state36.contributions += 1;
14943
14944
  api.metrics.counter("system_prompt_contribution");
14944
- const lines = state37.wraps.map(
14945
+ const lines = state36.wraps.map(
14945
14946
  (w, i) => `${i + 1}. ${w.plugin} [${w.kind}] wraps: ${w.wraps.join(", ")}`
14946
14947
  );
14947
14948
  return [
@@ -14967,9 +14968,9 @@ Any failure or latency above is attributable to one of the above.`
14967
14968
  ok: true,
14968
14969
  enabled: cfg.enabled,
14969
14970
  injectIntoSystemPrompt: cfg.injectIntoSystemPrompt,
14970
- wrapCount: state37.wraps.length,
14971
- wraps: state37.wraps,
14972
- contributions: state37.contributions
14971
+ wrapCount: state36.wraps.length,
14972
+ wraps: state36.wraps,
14973
+ contributions: state36.contributions
14973
14974
  };
14974
14975
  }
14975
14976
  });
@@ -14980,20 +14981,20 @@ Any failure or latency above is attributable to one of the above.`
14980
14981
  },
14981
14982
  teardown(api) {
14982
14983
  const final = {
14983
- wrapCount: state37.wraps.length,
14984
- contributions: state37.contributions
14984
+ wrapCount: state36.wraps.length,
14985
+ contributions: state36.contributions
14985
14986
  };
14986
14987
  clearObserverState();
14987
14988
  api.log.info("plugin-stack-observer: teardown complete", { final });
14988
14989
  },
14989
14990
  async health() {
14990
- const stack = state37.wraps.length === 0 ? "no wraps active" : state37.wraps.map((w) => w.plugin).join(" \u2192 ");
14991
+ const stack = state36.wraps.length === 0 ? "no wraps active" : state36.wraps.map((w) => w.plugin).join(" \u2192 ");
14991
14992
  return {
14992
14993
  ok: true,
14993
- message: `plugin-stack-observer: ${state37.wraps.length} wrap(s) loaded [${stack}]`,
14994
- wrapCount: state37.wraps.length,
14995
- contributions: state37.contributions,
14996
- wraps: state37.wraps
14994
+ message: `plugin-stack-observer: ${state36.wraps.length} wrap(s) loaded [${stack}]`,
14995
+ wrapCount: state36.wraps.length,
14996
+ contributions: state36.contributions,
14997
+ wraps: state36.wraps
14997
14998
  };
14998
14999
  }
14999
15000
  };
@@ -15012,7 +15013,7 @@ import { execFile as execFile10 } from "node:child_process";
15012
15013
  import { mkdir as mkdir2, writeFile as writeFile3 } from "node:fs/promises";
15013
15014
  import { dirname as dirname7, isAbsolute as isAbsolute19, relative as relative19, resolve as resolve19 } from "node:path";
15014
15015
  var API_VERSION26 = "^0.1.10";
15015
- var state38 = {
15016
+ var state37 = {
15016
15017
  commits: [],
15017
15018
  files: /* @__PURE__ */ new Set(),
15018
15019
  models: /* @__PURE__ */ new Set(),
@@ -15089,10 +15090,10 @@ async function buildDraft(cfg, llm) {
15089
15090
  lines.push("");
15090
15091
  if (cfg.aiSummary && llm) {
15091
15092
  try {
15092
- const context = `Files changed: ${[...state38.files].join(", ") || "none"}
15093
- Commits: ${state38.commits.join("; ") || "none"}
15094
- Tool calls: ${state38.toolCalls}
15095
- Tokens: ${state38.totalInputTokens} in / ${state38.totalOutputTokens} out`;
15093
+ const context = `Files changed: ${[...state37.files].join(", ") || "none"}
15094
+ Commits: ${state37.commits.join("; ") || "none"}
15095
+ Tool calls: ${state37.toolCalls}
15096
+ Tokens: ${state37.totalInputTokens} in / ${state37.totalOutputTokens} out`;
15096
15097
  const result = await llm.complete(
15097
15098
  "Write a concise PR title and one-paragraph summary for the changes below. Format exactly as:\nTITLE: <title>\nSUMMARY: <summary>\n\n" + context,
15098
15099
  {
@@ -15109,14 +15110,14 @@ Tokens: ${state38.totalInputTokens} in / ${state38.totalOutputTokens} out`;
15109
15110
  } catch {
15110
15111
  }
15111
15112
  }
15112
- if (cfg.includeCommits && state38.commits.length > 0) {
15113
+ if (cfg.includeCommits && state37.commits.length > 0) {
15113
15114
  lines.push("## Commits");
15114
- for (const c of state38.commits) lines.push(`- ${c}`);
15115
+ for (const c of state37.commits) lines.push(`- ${c}`);
15115
15116
  lines.push("");
15116
15117
  }
15117
- if (cfg.includeFiles && state38.files.size > 0) {
15118
+ if (cfg.includeFiles && state37.files.size > 0) {
15118
15119
  lines.push("## Files changed");
15119
- for (const f of [...state38.files].sort()) lines.push(`- \`${f}\``);
15120
+ for (const f of [...state37.files].sort()) lines.push(`- \`${f}\``);
15120
15121
  lines.push("");
15121
15122
  }
15122
15123
  if (diffStat) {
@@ -15127,26 +15128,26 @@ Tokens: ${state38.totalInputTokens} in / ${state38.totalOutputTokens} out`;
15127
15128
  lines.push("");
15128
15129
  }
15129
15130
  lines.push("## Session metrics");
15130
- lines.push(`- Tool calls: ${state38.toolCalls}`);
15131
- lines.push(`- Models used: ${[...state38.models].join(", ") || "unknown"}`);
15132
- lines.push(`- Tokens: ${state38.totalInputTokens} in / ${state38.totalOutputTokens} out`);
15131
+ lines.push(`- Tool calls: ${state37.toolCalls}`);
15132
+ lines.push(`- Models used: ${[...state37.models].join(", ") || "unknown"}`);
15133
+ lines.push(`- Tokens: ${state37.totalInputTokens} in / ${state37.totalOutputTokens} out`);
15133
15134
  lines.push("");
15134
- const title = state38.commits[0] ?? `Changes on ${branch ?? "current branch"}`;
15135
+ const title = state37.commits[0] ?? `Changes on ${branch ?? "current branch"}`;
15135
15136
  return { title, body: lines.join("\n") };
15136
15137
  }
15137
15138
  async function writeDraft(cfg, llm) {
15138
15139
  const resolved = resolveProjectPath7(cfg.outputPath);
15139
15140
  if (!resolved) {
15140
- state38.draftErrors += 1;
15141
+ state37.draftErrors += 1;
15141
15142
  return;
15142
15143
  }
15143
15144
  const draft = await buildDraft(cfg, llm);
15144
15145
  try {
15145
15146
  await mkdir2(dirname7(resolved), { recursive: true });
15146
15147
  await writeFile3(resolved, draft.body);
15147
- state38.draftsWritten += 1;
15148
+ state37.draftsWritten += 1;
15148
15149
  } catch {
15149
- state38.draftErrors += 1;
15150
+ state37.draftErrors += 1;
15150
15151
  }
15151
15152
  }
15152
15153
  var plugin40 = {
@@ -15197,54 +15198,54 @@ var plugin40 = {
15197
15198
  }
15198
15199
  },
15199
15200
  setup(api) {
15200
- state38.commits = [];
15201
- state38.files = /* @__PURE__ */ new Set();
15202
- state38.models = /* @__PURE__ */ new Set();
15203
- state38.totalInputTokens = 0;
15204
- state38.totalOutputTokens = 0;
15205
- state38.toolCalls = 0;
15206
- state38.draftsWritten = 0;
15207
- state38.draftErrors = 0;
15208
- state38.stopInvocations = 0;
15209
- state38.stopHookUnregister = releaseHandle(state38.stopHookUnregister);
15210
- for (const off of state38.eventUnsubscribers) {
15201
+ state37.commits = [];
15202
+ state37.files = /* @__PURE__ */ new Set();
15203
+ state37.models = /* @__PURE__ */ new Set();
15204
+ state37.totalInputTokens = 0;
15205
+ state37.totalOutputTokens = 0;
15206
+ state37.toolCalls = 0;
15207
+ state37.draftsWritten = 0;
15208
+ state37.draftErrors = 0;
15209
+ state37.stopInvocations = 0;
15210
+ state37.stopHookUnregister = releaseHandle(state37.stopHookUnregister);
15211
+ for (const off of state37.eventUnsubscribers) {
15211
15212
  try {
15212
15213
  off();
15213
15214
  } catch {
15214
15215
  }
15215
15216
  }
15216
- state38.eventUnsubscribers = [];
15217
+ state37.eventUnsubscribers = [];
15217
15218
  const cfg = readConfig36(api.config.extensions?.["pr-drafter"]);
15218
15219
  if (api.onPattern) {
15219
15220
  const offTool = api.onPattern("tool.completed", (_event, payload) => {
15220
15221
  const p = payload;
15221
15222
  const toolName = p?.tool;
15222
- state38.toolCalls += 1;
15223
+ state37.toolCalls += 1;
15223
15224
  if (toolName === "git_autocommit" && p?.result?.committed) {
15224
15225
  const msg = p.result.commitMessage ?? p.input?.message ?? "commit";
15225
- state38.commits.push(msg);
15226
+ state37.commits.push(msg);
15226
15227
  }
15227
15228
  if ((toolName === "write" || toolName === "edit") && p?.input?.path) {
15228
- state38.files.add(p.input.path);
15229
+ state37.files.add(p.input.path);
15229
15230
  }
15230
15231
  });
15231
- state38.eventUnsubscribers.push(offTool);
15232
+ state37.eventUnsubscribers.push(offTool);
15232
15233
  }
15233
15234
  if (api.onEvent) {
15234
15235
  const offUsage = api.onEvent("provider.response", (payload) => {
15235
15236
  const p = payload;
15236
- if (p?.model) state38.models.add(p.model);
15237
- state38.totalInputTokens += p?.usage?.input ?? 0;
15238
- state38.totalOutputTokens += p?.usage?.output ?? 0;
15237
+ if (p?.model) state37.models.add(p.model);
15238
+ state37.totalInputTokens += p?.usage?.input ?? 0;
15239
+ state37.totalOutputTokens += p?.usage?.output ?? 0;
15239
15240
  });
15240
- state38.eventUnsubscribers.push(offUsage);
15241
+ state37.eventUnsubscribers.push(offUsage);
15241
15242
  }
15242
15243
  const stopHook = async () => {
15243
15244
  if (!cfg.enabled || !cfg.writeOnStop) return;
15244
- state38.stopInvocations += 1;
15245
+ state37.stopInvocations += 1;
15245
15246
  await writeDraft(cfg, api.llm);
15246
15247
  };
15247
- state38.stopHookUnregister = api.registerHook("Stop", void 0, stopHook);
15248
+ state37.stopHookUnregister = api.registerHook("Stop", void 0, stopHook);
15248
15249
  api.tools.register({
15249
15250
  name: "pr_draft",
15250
15251
  description: "Generate or refresh the pull-request draft for the current session. Writes the markdown file and returns its path + title.",
@@ -15277,7 +15278,7 @@ var plugin40 = {
15277
15278
  try {
15278
15279
  await mkdir2(dirname7(resolved), { recursive: true });
15279
15280
  await writeFile3(resolved, draft.body);
15280
- state38.draftsWritten += 1;
15281
+ state37.draftsWritten += 1;
15281
15282
  return {
15282
15283
  ok: true,
15283
15284
  path: cfg.outputPath,
@@ -15285,7 +15286,7 @@ var plugin40 = {
15285
15286
  title: draft.title
15286
15287
  };
15287
15288
  } catch (err) {
15288
- state38.draftErrors += 1;
15289
+ state37.draftErrors += 1;
15289
15290
  return {
15290
15291
  ok: false,
15291
15292
  error: err instanceof Error ? err.message : String(err)
@@ -15300,48 +15301,48 @@ var plugin40 = {
15300
15301
  });
15301
15302
  },
15302
15303
  teardown(api) {
15303
- if (state38.stopHookUnregister) {
15304
+ if (state37.stopHookUnregister) {
15304
15305
  try {
15305
- state38.stopHookUnregister();
15306
+ state37.stopHookUnregister();
15306
15307
  } catch {
15307
15308
  }
15308
- state38.stopHookUnregister = null;
15309
+ state37.stopHookUnregister = null;
15309
15310
  }
15310
- for (const off of state38.eventUnsubscribers) {
15311
+ for (const off of state37.eventUnsubscribers) {
15311
15312
  try {
15312
15313
  off();
15313
15314
  } catch {
15314
15315
  }
15315
15316
  }
15316
- state38.eventUnsubscribers = [];
15317
+ state37.eventUnsubscribers = [];
15317
15318
  const final = {
15318
- commits: state38.commits.length,
15319
- files: state38.files.size,
15320
- toolCalls: state38.toolCalls,
15321
- draftsWritten: state38.draftsWritten,
15322
- draftErrors: state38.draftErrors
15319
+ commits: state37.commits.length,
15320
+ files: state37.files.size,
15321
+ toolCalls: state37.toolCalls,
15322
+ draftsWritten: state37.draftsWritten,
15323
+ draftErrors: state37.draftErrors
15323
15324
  };
15324
- state38.commits = [];
15325
- state38.files = /* @__PURE__ */ new Set();
15326
- state38.models = /* @__PURE__ */ new Set();
15327
- state38.totalInputTokens = 0;
15328
- state38.totalOutputTokens = 0;
15329
- state38.toolCalls = 0;
15330
- state38.draftsWritten = 0;
15331
- state38.draftErrors = 0;
15332
- state38.stopInvocations = 0;
15325
+ state37.commits = [];
15326
+ state37.files = /* @__PURE__ */ new Set();
15327
+ state37.models = /* @__PURE__ */ new Set();
15328
+ state37.totalInputTokens = 0;
15329
+ state37.totalOutputTokens = 0;
15330
+ state37.toolCalls = 0;
15331
+ state37.draftsWritten = 0;
15332
+ state37.draftErrors = 0;
15333
+ state37.stopInvocations = 0;
15333
15334
  api.log.info("pr-drafter: teardown complete", { final });
15334
15335
  },
15335
15336
  async health() {
15336
15337
  return {
15337
- ok: state38.draftErrors === 0,
15338
- message: `pr-drafter: ${state38.commits.length} commit(s), ${state38.files.size} file(s), ${state38.draftsWritten} draft(s) written, ${state38.draftErrors} error(s)`,
15338
+ ok: state37.draftErrors === 0,
15339
+ message: `pr-drafter: ${state37.commits.length} commit(s), ${state37.files.size} file(s), ${state37.draftsWritten} draft(s) written, ${state37.draftErrors} error(s)`,
15339
15340
  counters: {
15340
- commits: state38.commits.length,
15341
- files: state38.files.size,
15342
- toolCalls: state38.toolCalls,
15343
- draftsWritten: state38.draftsWritten,
15344
- draftErrors: state38.draftErrors
15341
+ commits: state37.commits.length,
15342
+ files: state37.files.size,
15343
+ toolCalls: state37.toolCalls,
15344
+ draftsWritten: state37.draftsWritten,
15345
+ draftErrors: state37.draftErrors
15345
15346
  }
15346
15347
  };
15347
15348
  }
@@ -15350,7 +15351,7 @@ var pr_drafter_default = plugin40;
15350
15351
 
15351
15352
  // src/process-guard/index.ts
15352
15353
  import * as os from "node:os";
15353
- var state39 = {
15354
+ var state38 = {
15354
15355
  invocations: 0,
15355
15356
  detections: 0,
15356
15357
  warns: 0,
@@ -15389,16 +15390,16 @@ var plugin41 = {
15389
15390
  }
15390
15391
  },
15391
15392
  setup(api) {
15392
- state39.invocations = 0;
15393
- state39.detections = 0;
15394
- state39.warns = 0;
15395
- state39.lastDetection = null;
15396
- if (state39.hookUnregister) {
15393
+ state38.invocations = 0;
15394
+ state38.detections = 0;
15395
+ state38.warns = 0;
15396
+ state38.lastDetection = null;
15397
+ if (state38.hookUnregister) {
15397
15398
  try {
15398
- state39.hookUnregister();
15399
+ state38.hookUnregister();
15399
15400
  } catch {
15400
15401
  }
15401
- state39.hookUnregister = null;
15402
+ state38.hookUnregister = null;
15402
15403
  }
15403
15404
  const cfg = readConfig37(api.config.extensions?.["process-guard"]);
15404
15405
  if (cfg.mode === "off") {
@@ -15407,7 +15408,7 @@ var plugin41 = {
15407
15408
  }
15408
15409
  const hook = (input) => {
15409
15410
  if (!cfg.enabled || cfg.mode === "off") return;
15410
- state39.invocations += 1;
15411
+ state38.invocations += 1;
15411
15412
  const toolName = input.toolName ?? "";
15412
15413
  if (toolName !== "bash" && toolName !== "exec") return;
15413
15414
  const ti = input.toolInput ?? {};
@@ -15416,8 +15417,8 @@ var plugin41 = {
15416
15417
  const cmdLower = command.toLowerCase();
15417
15418
  const isKillRelated = cmdLower.includes("kill") || cmdLower.includes("taskkill") || cmdLower.includes("stop-process") || cmdLower.includes("tskill") || cmdLower.includes("pkill") || cmdLower.includes("killall") || cmdLower.includes("wmic");
15418
15419
  if (!isKillRelated) return;
15419
- state39.detections += 1;
15420
- state39.lastDetection = {
15420
+ state38.detections += 1;
15421
+ state38.lastDetection = {
15421
15422
  target: command.slice(0, 100),
15422
15423
  tool: toolName,
15423
15424
  when: (/* @__PURE__ */ new Date()).toISOString()
@@ -15431,7 +15432,7 @@ var plugin41 = {
15431
15432
  }
15432
15433
  );
15433
15434
  };
15434
- state39.hookUnregister = api.registerHook("PreToolUse", "bash|exec", hook, {
15435
+ state38.hookUnregister = api.registerHook("PreToolUse", "bash|exec", hook, {
15435
15436
  name: "process-guard",
15436
15437
  stage: "validate",
15437
15438
  failurePolicy: "closed",
@@ -15453,11 +15454,11 @@ var plugin41 = {
15453
15454
  selfPid: process.pid,
15454
15455
  parentPid: process.ppid,
15455
15456
  counters: {
15456
- invocations: state39.invocations,
15457
- detections: state39.detections,
15458
- warns: state39.warns
15457
+ invocations: state38.invocations,
15458
+ detections: state38.detections,
15459
+ warns: state38.warns
15459
15460
  },
15460
- lastDetection: state39.lastDetection
15461
+ lastDetection: state38.lastDetection
15461
15462
  };
15462
15463
  }
15463
15464
  });
@@ -15470,27 +15471,27 @@ var plugin41 = {
15470
15471
  });
15471
15472
  },
15472
15473
  teardown(api) {
15473
- if (state39.hookUnregister) {
15474
+ if (state38.hookUnregister) {
15474
15475
  try {
15475
- state39.hookUnregister();
15476
+ state38.hookUnregister();
15476
15477
  } catch {
15477
15478
  }
15478
- state39.hookUnregister = null;
15479
+ state38.hookUnregister = null;
15479
15480
  }
15480
15481
  const final = {
15481
- invocations: state39.invocations,
15482
- detections: state39.detections,
15483
- warns: state39.warns
15482
+ invocations: state38.invocations,
15483
+ detections: state38.detections,
15484
+ warns: state38.warns
15484
15485
  };
15485
- state39.invocations = 0;
15486
- state39.detections = 0;
15487
- state39.warns = 0;
15486
+ state38.invocations = 0;
15487
+ state38.detections = 0;
15488
+ state38.warns = 0;
15488
15489
  api.log.info("[process-guard] teardown complete", { final });
15489
15490
  },
15490
15491
  async health() {
15491
15492
  return {
15492
15493
  ok: true,
15493
- message: state39.lastDetection === null ? `process-guard: ${state39.invocations} invocation(s), ${state39.detections} detection(s), ${state39.warns} warn(s)` : `process-guard: last detection on "${state39.lastDetection.tool}" at ${state39.lastDetection.when}`
15494
+ message: state38.lastDetection === null ? `process-guard: ${state38.invocations} invocation(s), ${state38.detections} detection(s), ${state38.warns} warn(s)` : `process-guard: last detection on "${state38.lastDetection.tool}" at ${state38.lastDetection.when}`
15494
15495
  };
15495
15496
  }
15496
15497
  };
@@ -15723,7 +15724,7 @@ function readConfig38(raw) {
15723
15724
  allow
15724
15725
  };
15725
15726
  }
15726
- var state40 = {
15727
+ var state39 = {
15727
15728
  invocations: 0,
15728
15729
  requestsWithSecrets: 0,
15729
15730
  requestRedactions: 0,
@@ -15768,19 +15769,19 @@ var plugin42 = {
15768
15769
  }
15769
15770
  },
15770
15771
  setup(api) {
15771
- state40.invocations = 0;
15772
- state40.requestsWithSecrets = 0;
15773
- state40.requestRedactions = 0;
15774
- state40.responseRedactions = 0;
15775
- state40.blocked = 0;
15776
- state40.byKind.clear();
15777
- state40.lastDetection = null;
15778
- if (state40.extensionUnregister) {
15772
+ state39.invocations = 0;
15773
+ state39.requestsWithSecrets = 0;
15774
+ state39.requestRedactions = 0;
15775
+ state39.responseRedactions = 0;
15776
+ state39.blocked = 0;
15777
+ state39.byKind.clear();
15778
+ state39.lastDetection = null;
15779
+ if (state39.extensionUnregister) {
15779
15780
  try {
15780
- state40.extensionUnregister();
15781
+ state39.extensionUnregister();
15781
15782
  } catch {
15782
15783
  }
15783
- state40.extensionUnregister = null;
15784
+ state39.extensionUnregister = null;
15784
15785
  }
15785
15786
  const cfg = readConfig38(api.config.extensions?.["prompt-firewall"]);
15786
15787
  if (cfg.enabled) {
@@ -15789,25 +15790,25 @@ var plugin42 = {
15789
15790
  kind: "security",
15790
15791
  wraps: ["request", "response"]
15791
15792
  });
15792
- state40.extensionUnregister = api.extensions.register({
15793
+ state39.extensionUnregister = api.extensions.register({
15793
15794
  name: "prompt-firewall",
15794
15795
  owner: "prompt-firewall",
15795
15796
  async wrapProviderRunner(_ctx, request, inner) {
15796
15797
  const req = request ?? {};
15797
- state40.invocations += 1;
15798
+ state39.invocations += 1;
15798
15799
  const detections = detectSecrets(collectText(req), cfg.allow);
15799
15800
  if (detections.length > 0) {
15800
- state40.requestsWithSecrets += 1;
15801
+ state39.requestsWithSecrets += 1;
15801
15802
  for (const d of detections) {
15802
- state40.byKind.set(d.kind, (state40.byKind.get(d.kind) ?? 0) + d.count);
15803
+ state39.byKind.set(d.kind, (state39.byKind.get(d.kind) ?? 0) + d.count);
15803
15804
  }
15804
15805
  const kinds = detections.map((d) => d.kind);
15805
- state40.lastDetection = { where: "request", kinds, when: (/* @__PURE__ */ new Date()).toISOString() };
15806
+ state39.lastDetection = { where: "request", kinds, when: (/* @__PURE__ */ new Date()).toISOString() };
15806
15807
  api.metrics.counter("request_leaks", 1);
15807
15808
  api.log.warn("prompt-firewall: secrets detected in outgoing request", { kinds });
15808
15809
  api.emitCustom("prompt-firewall:leak", { where: "request", kinds });
15809
15810
  if (cfg.mode === "block") {
15810
- state40.blocked += 1;
15811
+ state39.blocked += 1;
15811
15812
  throw new Error(
15812
15813
  `prompt-firewall blocked a provider call: outgoing context contains credential-shaped data (${kinds.join(", ")}). Remove the secret from context, add an \`allow\` pattern, or switch mode to "warn".`
15813
15814
  );
@@ -15815,7 +15816,7 @@ var plugin42 = {
15815
15816
  if (cfg.mode === "redact") {
15816
15817
  const counter = { n: 0 };
15817
15818
  const redactedReq = redactDeep(req, cfg.allow, counter);
15818
- state40.requestRedactions += counter.n;
15819
+ state39.requestRedactions += counter.n;
15819
15820
  api.metrics.counter("request_redactions", counter.n);
15820
15821
  const response2 = await inner(_ctx, redactedReq);
15821
15822
  return cfg.scanResponse ? redactResponse(response2, cfg.allow) : response2;
@@ -15836,9 +15837,9 @@ var plugin42 = {
15836
15837
  if (content === void 0) return response;
15837
15838
  const redacted = redactDeep(content, allow, counter);
15838
15839
  if (counter.n > 0) {
15839
- state40.responseRedactions += counter.n;
15840
+ state39.responseRedactions += counter.n;
15840
15841
  api.metrics.counter("response_redactions", counter.n);
15841
- state40.lastDetection = {
15842
+ state39.lastDetection = {
15842
15843
  where: "response",
15843
15844
  kinds: ["echoed-secret"],
15844
15845
  when: (/* @__PURE__ */ new Date()).toISOString()
@@ -15861,14 +15862,14 @@ var plugin42 = {
15861
15862
  scanResponse: cfg.scanResponse,
15862
15863
  patterns: PATTERNS2.map((p) => p.kind),
15863
15864
  counters: {
15864
- invocations: state40.invocations,
15865
- requestsWithSecrets: state40.requestsWithSecrets,
15866
- requestRedactions: state40.requestRedactions,
15867
- responseRedactions: state40.responseRedactions,
15868
- blocked: state40.blocked
15865
+ invocations: state39.invocations,
15866
+ requestsWithSecrets: state39.requestsWithSecrets,
15867
+ requestRedactions: state39.requestRedactions,
15868
+ responseRedactions: state39.responseRedactions,
15869
+ blocked: state39.blocked
15869
15870
  },
15870
- byKind: Object.fromEntries(state40.byKind),
15871
- lastDetection: state40.lastDetection
15871
+ byKind: Object.fromEntries(state39.byKind),
15872
+ lastDetection: state39.lastDetection
15872
15873
  };
15873
15874
  }
15874
15875
  });
@@ -15880,39 +15881,39 @@ var plugin42 = {
15880
15881
  });
15881
15882
  },
15882
15883
  teardown(api) {
15883
- if (state40.extensionUnregister) {
15884
+ if (state39.extensionUnregister) {
15884
15885
  try {
15885
- state40.extensionUnregister();
15886
+ state39.extensionUnregister();
15886
15887
  } catch {
15887
15888
  }
15888
- state40.extensionUnregister = null;
15889
+ state39.extensionUnregister = null;
15889
15890
  }
15890
15891
  const final = {
15891
- invocations: state40.invocations,
15892
- requestsWithSecrets: state40.requestsWithSecrets,
15893
- requestRedactions: state40.requestRedactions,
15894
- responseRedactions: state40.responseRedactions,
15895
- blocked: state40.blocked
15892
+ invocations: state39.invocations,
15893
+ requestsWithSecrets: state39.requestsWithSecrets,
15894
+ requestRedactions: state39.requestRedactions,
15895
+ responseRedactions: state39.responseRedactions,
15896
+ blocked: state39.blocked
15896
15897
  };
15897
- state40.invocations = 0;
15898
- state40.requestsWithSecrets = 0;
15899
- state40.requestRedactions = 0;
15900
- state40.responseRedactions = 0;
15901
- state40.blocked = 0;
15902
- state40.byKind.clear();
15903
- state40.lastDetection = null;
15898
+ state39.invocations = 0;
15899
+ state39.requestsWithSecrets = 0;
15900
+ state39.requestRedactions = 0;
15901
+ state39.responseRedactions = 0;
15902
+ state39.blocked = 0;
15903
+ state39.byKind.clear();
15904
+ state39.lastDetection = null;
15904
15905
  api.log.info("prompt-firewall: teardown complete", { final });
15905
15906
  },
15906
15907
  async health() {
15907
15908
  return {
15908
15909
  ok: true,
15909
- message: `prompt-firewall: ${state40.requestsWithSecrets} request(s) with secrets, ${state40.requestRedactions} request redaction(s), ${state40.blocked} blocked`,
15910
+ message: `prompt-firewall: ${state39.requestsWithSecrets} request(s) with secrets, ${state39.requestRedactions} request redaction(s), ${state39.blocked} blocked`,
15910
15911
  counters: {
15911
- invocations: state40.invocations,
15912
- requestsWithSecrets: state40.requestsWithSecrets,
15913
- requestRedactions: state40.requestRedactions,
15914
- responseRedactions: state40.responseRedactions,
15915
- blocked: state40.blocked
15912
+ invocations: state39.invocations,
15913
+ requestsWithSecrets: state39.requestsWithSecrets,
15914
+ requestRedactions: state39.requestRedactions,
15915
+ responseRedactions: state39.responseRedactions,
15916
+ blocked: state39.blocked
15916
15917
  }
15917
15918
  };
15918
15919
  }
@@ -15924,7 +15925,7 @@ import { readFile as readFile11 } from "node:fs/promises";
15924
15925
  import { isAbsolute as isAbsolute20, relative as relative20, resolve as resolve20 } from "node:path";
15925
15926
  var API_VERSION27 = "^0.1.10";
15926
15927
  var HOOK_WARNING_COOLDOWN_MS2 = 6e4;
15927
- var state41 = {
15928
+ var state40 = {
15928
15929
  scanCount: 0,
15929
15930
  suggestionCount: 0,
15930
15931
  hookInvocationCount: 0,
@@ -16112,18 +16113,18 @@ var plugin43 = {
16112
16113
  }
16113
16114
  },
16114
16115
  setup(api) {
16115
- state41.scanCount = 0;
16116
- state41.suggestionCount = 0;
16117
- state41.hookInvocationCount = 0;
16118
- state41.warningCount = 0;
16119
- state41.errorCount = 0;
16120
- state41.lastHookWarning.clear();
16121
- if (state41.hookUnregister) {
16116
+ state40.scanCount = 0;
16117
+ state40.suggestionCount = 0;
16118
+ state40.hookInvocationCount = 0;
16119
+ state40.warningCount = 0;
16120
+ state40.errorCount = 0;
16121
+ state40.lastHookWarning.clear();
16122
+ if (state40.hookUnregister) {
16122
16123
  try {
16123
- state41.hookUnregister();
16124
+ state40.hookUnregister();
16124
16125
  } catch {
16125
16126
  }
16126
- state41.hookUnregister = null;
16127
+ state40.hookUnregister = null;
16127
16128
  }
16128
16129
  const cfg = readConfig39(api.config.extensions?.["refactor-suggester"]);
16129
16130
  const hook = async (input) => {
@@ -16135,28 +16136,28 @@ var plugin43 = {
16135
16136
  if (!withinProject(sourcePath)) return;
16136
16137
  const exts = normalizeExtensions5(cfg.extensions);
16137
16138
  if (!matchesExtension(sourcePath, exts)) return;
16138
- state41.hookInvocationCount += 1;
16139
+ state40.hookInvocationCount += 1;
16139
16140
  const now = Date.now();
16140
- const lastWarning = state41.lastHookWarning.get(sourcePath);
16141
+ const lastWarning = state40.lastHookWarning.get(sourcePath);
16141
16142
  if (lastWarning !== void 0 && now - lastWarning < HOOK_WARNING_COOLDOWN_MS2) return;
16142
16143
  const resolved = resolve20(process.cwd(), sourcePath);
16143
16144
  let content;
16144
16145
  try {
16145
16146
  content = await readFile11(resolved, "utf-8");
16146
16147
  } catch {
16147
- state41.errorCount += 1;
16148
+ state40.errorCount += 1;
16148
16149
  return;
16149
16150
  }
16150
16151
  const suggestions = detectSmells(resolved, content, cfg.rules);
16151
16152
  if (suggestions.length === 0) return;
16152
- state41.warningCount += suggestions.length;
16153
- state41.lastHookWarning.set(sourcePath, now);
16153
+ state40.warningCount += suggestions.length;
16154
+ state40.lastHookWarning.set(sourcePath, now);
16154
16155
  return {
16155
16156
  additionalContext: `\u{1F527} refactor-suggester: ${suggestions.length} suggestion(s) for ${sourcePath}. Run suggest_refactors for the full list.`,
16156
16157
  contextAs: "separate"
16157
16158
  };
16158
16159
  };
16159
- state41.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
16160
+ state40.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
16160
16161
  api.tools.register({
16161
16162
  name: "suggest_refactors",
16162
16163
  description: "Scan source files for refactoring smells: long functions, deep nesting, many parameters, magic numbers, and console logging.",
@@ -16175,15 +16176,15 @@ var plugin43 = {
16175
16176
  if (!withinProject(rawPath)) {
16176
16177
  return { ok: false, error: "path is outside the project root" };
16177
16178
  }
16178
- state41.scanCount += 1;
16179
+ state40.scanCount += 1;
16179
16180
  let result;
16180
16181
  try {
16181
16182
  result = await scanPath4(rawPath, cfg);
16182
16183
  } catch (err) {
16183
- state41.errorCount += 1;
16184
+ state40.errorCount += 1;
16184
16185
  return { ok: false, error: String(err) };
16185
16186
  }
16186
- state41.suggestionCount += result.suggestions.length;
16187
+ state40.suggestionCount += result.suggestions.length;
16187
16188
  return {
16188
16189
  ok: true,
16189
16190
  path: relativePath6(resolve20(process.cwd(), rawPath)),
@@ -16212,11 +16213,11 @@ var plugin43 = {
16212
16213
  maxSuggestions: cfg.maxSuggestions,
16213
16214
  rules: cfg.rules,
16214
16215
  counters: {
16215
- scans: state41.scanCount,
16216
- suggestions: state41.suggestionCount,
16217
- hookInvocations: state41.hookInvocationCount,
16218
- warnings: state41.warningCount,
16219
- errors: state41.errorCount
16216
+ scans: state40.scanCount,
16217
+ suggestions: state40.suggestionCount,
16218
+ hookInvocations: state40.hookInvocationCount,
16219
+ warnings: state40.warningCount,
16220
+ errors: state40.errorCount
16220
16221
  }
16221
16222
  };
16222
16223
  }
@@ -16228,38 +16229,38 @@ var plugin43 = {
16228
16229
  });
16229
16230
  },
16230
16231
  teardown(api) {
16231
- if (state41.hookUnregister) {
16232
+ if (state40.hookUnregister) {
16232
16233
  try {
16233
- state41.hookUnregister();
16234
+ state40.hookUnregister();
16234
16235
  } catch {
16235
16236
  }
16236
- state41.hookUnregister = null;
16237
+ state40.hookUnregister = null;
16237
16238
  }
16238
16239
  const final = {
16239
- scans: state41.scanCount,
16240
- suggestions: state41.suggestionCount,
16241
- hookInvocations: state41.hookInvocationCount,
16242
- warnings: state41.warningCount,
16243
- errors: state41.errorCount
16240
+ scans: state40.scanCount,
16241
+ suggestions: state40.suggestionCount,
16242
+ hookInvocations: state40.hookInvocationCount,
16243
+ warnings: state40.warningCount,
16244
+ errors: state40.errorCount
16244
16245
  };
16245
- state41.scanCount = 0;
16246
- state41.suggestionCount = 0;
16247
- state41.hookInvocationCount = 0;
16248
- state41.warningCount = 0;
16249
- state41.errorCount = 0;
16250
- state41.lastHookWarning.clear();
16246
+ state40.scanCount = 0;
16247
+ state40.suggestionCount = 0;
16248
+ state40.hookInvocationCount = 0;
16249
+ state40.warningCount = 0;
16250
+ state40.errorCount = 0;
16251
+ state40.lastHookWarning.clear();
16251
16252
  api.log.info("refactor-suggester: teardown complete", { final });
16252
16253
  },
16253
16254
  async health() {
16254
16255
  return {
16255
- ok: state41.errorCount === 0,
16256
- message: state41.errorCount ? `refactor-suggester: ${state41.errorCount} error(s)` : `refactor-suggester: ${state41.scanCount} scan(s), ${state41.suggestionCount} suggestion(s)`,
16256
+ ok: state40.errorCount === 0,
16257
+ message: state40.errorCount ? `refactor-suggester: ${state40.errorCount} error(s)` : `refactor-suggester: ${state40.scanCount} scan(s), ${state40.suggestionCount} suggestion(s)`,
16257
16258
  counters: {
16258
- scans: state41.scanCount,
16259
- suggestions: state41.suggestionCount,
16260
- hookInvocations: state41.hookInvocationCount,
16261
- warnings: state41.warningCount,
16262
- errors: state41.errorCount
16259
+ scans: state40.scanCount,
16260
+ suggestions: state40.suggestionCount,
16261
+ hookInvocations: state40.hookInvocationCount,
16262
+ warnings: state40.warningCount,
16263
+ errors: state40.errorCount
16263
16264
  }
16264
16265
  };
16265
16266
  }
@@ -16269,7 +16270,7 @@ var refactor_suggester_default = plugin43;
16269
16270
  // src/release-notes-generator/index.ts
16270
16271
  import { execFile as execFile11 } from "node:child_process";
16271
16272
  var API_VERSION28 = "^0.1.10";
16272
- var state42 = {
16273
+ var state41 = {
16273
16274
  generateCount: 0,
16274
16275
  commitCount: 0,
16275
16276
  errorCount: 0,
@@ -16474,11 +16475,11 @@ var plugin44 = {
16474
16475
  }
16475
16476
  },
16476
16477
  setup(api) {
16477
- state42.generateCount = 0;
16478
- state42.commitCount = 0;
16479
- state42.errorCount = 0;
16480
- state42.llmPolishCount = 0;
16481
- state42.llmFallbackCount = 0;
16478
+ state41.generateCount = 0;
16479
+ state41.commitCount = 0;
16480
+ state41.errorCount = 0;
16481
+ state41.llmPolishCount = 0;
16482
+ state41.llmFallbackCount = 0;
16482
16483
  const cfg = readConfig40(api.config.extensions?.["release-notes-generator"]);
16483
16484
  api.tools.register({
16484
16485
  name: "generate_release_notes",
@@ -16514,15 +16515,15 @@ var plugin44 = {
16514
16515
  execOpts?.signal?.throwIfAborted();
16515
16516
  const toRef = typeof input.to === "string" ? input.to : "HEAD";
16516
16517
  const fromRef = await resolveFromRef(cfg.defaultFrom, input.from, execOpts?.signal);
16517
- state42.generateCount += 1;
16518
+ state41.generateCount += 1;
16518
16519
  let commits;
16519
16520
  try {
16520
16521
  commits = await getCommits(fromRef, toRef, execOpts?.signal);
16521
16522
  } catch (err) {
16522
- state42.errorCount += 1;
16523
+ state41.errorCount += 1;
16523
16524
  return { ok: false, error: String(err) };
16524
16525
  }
16525
- state42.commitCount += commits.length;
16526
+ state41.commitCount += commits.length;
16526
16527
  execOpts?.signal?.throwIfAborted();
16527
16528
  const deterministicNotes = generateNotes(commits, cfg.includeScope);
16528
16529
  const requested = (input.use_llm ?? cfg.useLlm) && commits.length > 0;
@@ -16541,8 +16542,8 @@ var plugin44 = {
16541
16542
  },
16542
16543
  parse: (text) => parsePolishedNotes(text, commits)
16543
16544
  });
16544
- if (llm.used) state42.llmPolishCount += 1;
16545
- else if (requested) state42.llmFallbackCount += 1;
16545
+ if (llm.used) state41.llmPolishCount += 1;
16546
+ else if (requested) state41.llmFallbackCount += 1;
16546
16547
  api.metrics.counter("generations", 1);
16547
16548
  api.metrics.counter("commits_processed", commits.length);
16548
16549
  if (llm.used) api.metrics.counter("llm_polishes", 1, { audience });
@@ -16571,29 +16572,29 @@ var plugin44 = {
16571
16572
  },
16572
16573
  teardown(api) {
16573
16574
  const final = {
16574
- generated: state42.generateCount,
16575
- commits: state42.commitCount,
16576
- errors: state42.errorCount,
16577
- llmPolishes: state42.llmPolishCount,
16578
- llmFallbacks: state42.llmFallbackCount
16575
+ generated: state41.generateCount,
16576
+ commits: state41.commitCount,
16577
+ errors: state41.errorCount,
16578
+ llmPolishes: state41.llmPolishCount,
16579
+ llmFallbacks: state41.llmFallbackCount
16579
16580
  };
16580
- state42.generateCount = 0;
16581
- state42.commitCount = 0;
16582
- state42.errorCount = 0;
16583
- state42.llmPolishCount = 0;
16584
- state42.llmFallbackCount = 0;
16581
+ state41.generateCount = 0;
16582
+ state41.commitCount = 0;
16583
+ state41.errorCount = 0;
16584
+ state41.llmPolishCount = 0;
16585
+ state41.llmFallbackCount = 0;
16585
16586
  api.log.info("release-notes-generator: teardown complete", { final });
16586
16587
  },
16587
16588
  async health() {
16588
16589
  return {
16589
- ok: state42.errorCount === 0,
16590
- message: state42.errorCount ? `release-notes-generator: ${state42.errorCount} error(s)` : `release-notes-generator: ${state42.generateCount} generation(s), ${state42.commitCount} commit(s)`,
16590
+ ok: state41.errorCount === 0,
16591
+ message: state41.errorCount ? `release-notes-generator: ${state41.errorCount} error(s)` : `release-notes-generator: ${state41.generateCount} generation(s), ${state41.commitCount} commit(s)`,
16591
16592
  counters: {
16592
- generated: state42.generateCount,
16593
- commits: state42.commitCount,
16594
- errors: state42.errorCount,
16595
- llmPolishes: state42.llmPolishCount,
16596
- llmFallbacks: state42.llmFallbackCount
16593
+ generated: state41.generateCount,
16594
+ commits: state41.commitCount,
16595
+ errors: state41.errorCount,
16596
+ llmPolishes: state41.llmPolishCount,
16597
+ llmFallbacks: state41.llmFallbackCount
16597
16598
  }
16598
16599
  };
16599
16600
  }
@@ -16604,7 +16605,7 @@ var release_notes_generator_default = plugin44;
16604
16605
  import { readFileSync as readFileSync12 } from "node:fs";
16605
16606
  import { basename as basename5 } from "node:path";
16606
16607
  var API_VERSION29 = "^0.1.10";
16607
- var state43 = {
16608
+ var state42 = {
16608
16609
  invocationCount: 0,
16609
16610
  scannedCount: 0,
16610
16611
  skippedCount: 0,
@@ -16767,19 +16768,19 @@ var plugin45 = {
16767
16768
  }
16768
16769
  },
16769
16770
  setup(api) {
16770
- state43.invocationCount = 0;
16771
- state43.scannedCount = 0;
16772
- state43.skippedCount = 0;
16773
- state43.hitCount = 0;
16774
- state43.warningCount = 0;
16775
- state43.blockedCount = 0;
16776
- state43.lastFinding = null;
16777
- if (state43.hookUnregister) {
16771
+ state42.invocationCount = 0;
16772
+ state42.scannedCount = 0;
16773
+ state42.skippedCount = 0;
16774
+ state42.hitCount = 0;
16775
+ state42.warningCount = 0;
16776
+ state42.blockedCount = 0;
16777
+ state42.lastFinding = null;
16778
+ if (state42.hookUnregister) {
16778
16779
  try {
16779
- state43.hookUnregister();
16780
+ state42.hookUnregister();
16780
16781
  } catch {
16781
16782
  }
16782
- state43.hookUnregister = null;
16783
+ state42.hookUnregister = null;
16783
16784
  }
16784
16785
  const cfg = readConfig41(api.config.extensions?.["schema-evolution-guard"]);
16785
16786
  const hook = (input) => {
@@ -16788,15 +16789,15 @@ var plugin45 = {
16788
16789
  const toolInput = input.toolInput ?? {};
16789
16790
  const filePath = typeof toolInput["path"] === "string" ? toolInput["path"] : void 0;
16790
16791
  if (!filePath) return;
16791
- state43.invocationCount += 1;
16792
+ state42.invocationCount += 1;
16792
16793
  const fileName = basename5(filePath);
16793
16794
  if (!matchesAnyPattern2(fileName, cfg.filePatterns)) {
16794
- state43.skippedCount += 1;
16795
+ state42.skippedCount += 1;
16795
16796
  return;
16796
16797
  }
16797
16798
  const kind = fileKind(fileName);
16798
16799
  if (!kind) {
16799
- state43.skippedCount += 1;
16800
+ state42.skippedCount += 1;
16800
16801
  return;
16801
16802
  }
16802
16803
  let content;
@@ -16810,14 +16811,14 @@ var plugin45 = {
16810
16811
  }
16811
16812
  }
16812
16813
  if (content === void 0) {
16813
- state43.skippedCount += 1;
16814
+ state42.skippedCount += 1;
16814
16815
  return;
16815
16816
  }
16816
- state43.scannedCount += 1;
16817
+ state42.scannedCount += 1;
16817
16818
  const findings = findIssues(content, kind, cfg.maxFindings);
16818
16819
  if (findings.length === 0) return;
16819
- state43.hitCount += 1;
16820
- state43.lastFinding = findings[0] ?? null;
16820
+ state42.hitCount += 1;
16821
+ state42.lastFinding = findings[0] ?? null;
16821
16822
  const header = `
16822
16823
  \u26A0\uFE0F schema-evolution-guard: destructive schema pattern(s) detected in ${filePath}`;
16823
16824
  const body = findings.map((f) => ` - ${f}`).join("\n");
@@ -16825,13 +16826,13 @@ var plugin45 = {
16825
16826
  const message = `${header}
16826
16827
  ${body}${suffix}`;
16827
16828
  if (cfg.failSeverity === "block") {
16828
- state43.blockedCount += 1;
16829
+ state42.blockedCount += 1;
16829
16830
  return { decision: "block", reason: message };
16830
16831
  }
16831
- state43.warningCount += 1;
16832
+ state42.warningCount += 1;
16832
16833
  return { additionalContext: message };
16833
16834
  };
16834
- state43.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
16835
+ state42.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
16835
16836
  api.tools.register({
16836
16837
  name: "schema_evolution_status",
16837
16838
  description: "Reports schema-evolution-guard state: config, file patterns, and per-session counters.",
@@ -16847,14 +16848,14 @@ ${body}${suffix}`;
16847
16848
  maxFindings: cfg.maxFindings,
16848
16849
  filePatterns: cfg.filePatterns,
16849
16850
  counters: {
16850
- invocations: state43.invocationCount,
16851
- scanned: state43.scannedCount,
16852
- skipped: state43.skippedCount,
16853
- hits: state43.hitCount,
16854
- warnings: state43.warningCount,
16855
- blocked: state43.blockedCount
16851
+ invocations: state42.invocationCount,
16852
+ scanned: state42.scannedCount,
16853
+ skipped: state42.skippedCount,
16854
+ hits: state42.hitCount,
16855
+ warnings: state42.warningCount,
16856
+ blocked: state42.blockedCount
16856
16857
  },
16857
- lastFinding: state43.lastFinding
16858
+ lastFinding: state42.lastFinding
16858
16859
  };
16859
16860
  }
16860
16861
  });
@@ -16865,43 +16866,43 @@ ${body}${suffix}`;
16865
16866
  });
16866
16867
  },
16867
16868
  teardown(api) {
16868
- if (state43.hookUnregister) {
16869
+ if (state42.hookUnregister) {
16869
16870
  try {
16870
- state43.hookUnregister();
16871
+ state42.hookUnregister();
16871
16872
  } catch {
16872
16873
  }
16873
- state43.hookUnregister = null;
16874
+ state42.hookUnregister = null;
16874
16875
  }
16875
16876
  const final = {
16876
- invocations: state43.invocationCount,
16877
- scanned: state43.scannedCount,
16878
- skipped: state43.skippedCount,
16879
- hits: state43.hitCount,
16880
- warnings: state43.warningCount,
16881
- blocked: state43.blockedCount
16877
+ invocations: state42.invocationCount,
16878
+ scanned: state42.scannedCount,
16879
+ skipped: state42.skippedCount,
16880
+ hits: state42.hitCount,
16881
+ warnings: state42.warningCount,
16882
+ blocked: state42.blockedCount
16882
16883
  };
16883
- state43.invocationCount = 0;
16884
- state43.scannedCount = 0;
16885
- state43.skippedCount = 0;
16886
- state43.hitCount = 0;
16887
- state43.warningCount = 0;
16888
- state43.blockedCount = 0;
16889
- state43.lastFinding = null;
16884
+ state42.invocationCount = 0;
16885
+ state42.scannedCount = 0;
16886
+ state42.skippedCount = 0;
16887
+ state42.hitCount = 0;
16888
+ state42.warningCount = 0;
16889
+ state42.blockedCount = 0;
16890
+ state42.lastFinding = null;
16890
16891
  api.log.info("schema-evolution-guard: teardown complete", { final });
16891
16892
  },
16892
16893
  async health() {
16893
16894
  return {
16894
16895
  ok: true,
16895
- message: `schema-evolution-guard: ${state43.scannedCount} scan(s), ${state43.hitCount} hit(s), ${state43.blockedCount} blocked`,
16896
+ message: `schema-evolution-guard: ${state42.scannedCount} scan(s), ${state42.hitCount} hit(s), ${state42.blockedCount} blocked`,
16896
16897
  counters: {
16897
- invocations: state43.invocationCount,
16898
- scanned: state43.scannedCount,
16899
- skipped: state43.skippedCount,
16900
- hits: state43.hitCount,
16901
- warnings: state43.warningCount,
16902
- blocked: state43.blockedCount
16903
- },
16904
- lastFinding: state43.lastFinding
16898
+ invocations: state42.invocationCount,
16899
+ scanned: state42.scannedCount,
16900
+ skipped: state42.skippedCount,
16901
+ hits: state42.hitCount,
16902
+ warnings: state42.warningCount,
16903
+ blocked: state42.blockedCount
16904
+ },
16905
+ lastFinding: state42.lastFinding
16905
16906
  };
16906
16907
  }
16907
16908
  };
@@ -16910,7 +16911,6 @@ var schema_evolution_guard_default = plugin45;
16910
16911
  // src/secret-scanner/index.ts
16911
16912
  var BASE_PATTERNS = cloneCredentialPatterns();
16912
16913
  var PATTERNS3 = [...BASE_PATTERNS];
16913
- var patternCacheKey = "";
16914
16914
  var GROUP_INDEX_OF_PATTERN = [];
16915
16915
  var COMBINED_REGEX = buildCombinedRegex(PATTERNS3);
16916
16916
  var SCAN_WINDOW_LENGTH = 1e5;
@@ -16933,11 +16933,6 @@ function patternTypeForGroups(groups) {
16933
16933
  return void 0;
16934
16934
  }
16935
16935
  function buildCombinedRegex(patterns) {
16936
- const newCacheKey = JSON.stringify(patterns.map((p) => [p.type, p.regex.source]));
16937
- if (newCacheKey === patternCacheKey && COMBINED_REGEX) {
16938
- return COMBINED_REGEX;
16939
- }
16940
- patternCacheKey = newCacheKey;
16941
16936
  const offsets = [];
16942
16937
  let cursor = 0;
16943
16938
  for (const p of patterns) {
@@ -16947,21 +16942,30 @@ function buildCombinedRegex(patterns) {
16947
16942
  GROUP_INDEX_OF_PATTERN = offsets;
16948
16943
  return new RegExp(patterns.map((p) => `(${p.regex.source})`).join("|"), "g");
16949
16944
  }
16950
- var state44 = {
16951
- blockCount: 0,
16952
- redactCount: 0,
16953
- allowCount: 0,
16954
- /** PostToolUse: secrets detected in tool output. */
16955
- leakCount: 0,
16956
- /** Most recent PreToolUse block — surfaced by `secret_scanner_status`. */
16957
- lastBlock: null,
16958
- /** Most recent PostToolUse leak — surfaced by `secret_scanner_status`. */
16959
- lastLeak: null,
16960
- /** PreToolUse hook handle so teardown can unregister. */
16961
- hookUnregister: null,
16962
- /** PostToolUse hook handle so teardown can unregister. */
16963
- postHookUnregister: null
16964
- };
16945
+ function createState2() {
16946
+ return {
16947
+ blockCount: 0,
16948
+ redactCount: 0,
16949
+ allowCount: 0,
16950
+ /** PostToolUse: secrets detected in tool output. */
16951
+ leakCount: 0,
16952
+ /** Most recent PreToolUse block — surfaced by `secret_scanner_status`. */
16953
+ lastBlock: null,
16954
+ /** Most recent PostToolUse leak — surfaced by `secret_scanner_status`. */
16955
+ lastLeak: null,
16956
+ /** PreToolUse hook handle so teardown can unregister. */
16957
+ hookUnregister: null,
16958
+ /** PostToolUse hook handle so teardown can unregister. */
16959
+ postHookUnregister: null
16960
+ };
16961
+ }
16962
+ var runtimes = /* @__PURE__ */ new WeakMap();
16963
+ var latestRuntime;
16964
+ function activateRuntime(runtime) {
16965
+ PATTERNS3 = runtime.patterns;
16966
+ COMBINED_REGEX = runtime.combinedRegex;
16967
+ GROUP_INDEX_OF_PATTERN = runtime.groupIndexes;
16968
+ }
16965
16969
  function scanWindow(window, found, startTime) {
16966
16970
  COMBINED_REGEX.lastIndex = 0;
16967
16971
  let m;
@@ -17107,8 +17111,10 @@ function readConfig42(raw) {
17107
17111
  customPatterns
17108
17112
  };
17109
17113
  }
17110
- function buildHook(cfg, log) {
17114
+ function buildHook(cfg, log, runtime) {
17111
17115
  return (input) => {
17116
+ activateRuntime(runtime);
17117
+ const { state: state59 } = runtime;
17112
17118
  if (!cfg.enabled) return;
17113
17119
  const toolName = input.toolName ?? "unknown";
17114
17120
  const matched = scanInput(input.toolInput);
@@ -17116,8 +17122,8 @@ function buildHook(cfg, log) {
17116
17122
  const summary = matched.join(", ");
17117
17123
  const when = (/* @__PURE__ */ new Date()).toISOString();
17118
17124
  if (cfg.mode === "block") {
17119
- state44.blockCount += 1;
17120
- state44.lastBlock = { toolName, matchedTypes: matched, when };
17125
+ state59.blockCount += 1;
17126
+ state59.lastBlock = { toolName, matchedTypes: matched, when };
17121
17127
  log.warn(`[secret-scanner] blocked ${toolName} \u2014 matched: ${summary}`);
17122
17128
  return {
17123
17129
  decision: "block",
@@ -17127,7 +17133,7 @@ function buildHook(cfg, log) {
17127
17133
  if (cfg.mode === "redact") {
17128
17134
  const redacted = redactInput(input.toolInput);
17129
17135
  if (redacted.ok && redacted.value !== null && typeof redacted.value === "object" && !Array.isArray(redacted.value)) {
17130
- state44.redactCount += 1;
17136
+ state59.redactCount += 1;
17131
17137
  log.info(`[secret-scanner] redacted ${toolName} \u2014 matched: ${summary}`);
17132
17138
  return {
17133
17139
  decision: "allow",
@@ -17135,23 +17141,25 @@ function buildHook(cfg, log) {
17135
17141
  additionalContext: `secret-scanner: redacted ${matched.length} credential pattern(s) from the ${toolName} arguments before execution.`
17136
17142
  };
17137
17143
  }
17138
- state44.blockCount += 1;
17139
- state44.lastBlock = { toolName, matchedTypes: matched, when };
17144
+ state59.blockCount += 1;
17145
+ state59.lastBlock = { toolName, matchedTypes: matched, when };
17140
17146
  const detail = !redacted.ok ? redacted.reason === "oversized_input" ? "an input field exceeds the safe scan limit" : "the input exceeds the safe nesting depth" : "the input has a non-object shape";
17141
17147
  return {
17142
17148
  decision: "block",
17143
17149
  reason: `secret-scanner: cannot safely redact '${toolName}' because ${detail}; refusing to run.`
17144
17150
  };
17145
17151
  }
17146
- state44.allowCount += 1;
17152
+ state59.allowCount += 1;
17147
17153
  log.warn(
17148
17154
  `[secret-scanner] allow-mode: ${toolName} matched ${summary} but mode='allow' lets it through.`
17149
17155
  );
17150
17156
  return void 0;
17151
17157
  };
17152
17158
  }
17153
- function buildPostHook(cfg, log) {
17159
+ function buildPostHook(cfg, log, runtime) {
17154
17160
  return (input) => {
17161
+ activateRuntime(runtime);
17162
+ const { state: state59 } = runtime;
17155
17163
  if (!cfg.enabled) return;
17156
17164
  const result = input.toolResult;
17157
17165
  if (!result || typeof result.content !== "string") return;
@@ -17171,8 +17179,8 @@ function buildPostHook(cfg, log) {
17171
17179
  }
17172
17180
  const summary = credentialMatches.join(", ");
17173
17181
  const when = (/* @__PURE__ */ new Date()).toISOString();
17174
- state44.leakCount += 1;
17175
- state44.lastLeak = { toolName, matchedTypes: credentialMatches, when };
17182
+ state59.leakCount += 1;
17183
+ state59.lastLeak = { toolName, matchedTypes: credentialMatches, when };
17176
17184
  log.warn(`[secret-scanner] POST-TOOL LEAK: ${toolName} output matched ${summary}`);
17177
17185
  return {
17178
17186
  additionalContext: `
@@ -17228,14 +17236,11 @@ var plugin46 = {
17228
17236
  }
17229
17237
  },
17230
17238
  setup(api) {
17231
- state44.blockCount = 0;
17232
- state44.redactCount = 0;
17233
- state44.allowCount = 0;
17234
- state44.leakCount = 0;
17235
- state44.lastBlock = null;
17236
- state44.lastLeak = null;
17237
- state44.hookUnregister = releaseHandle(state44.hookUnregister);
17238
- state44.postHookUnregister = releaseHandle(state44.postHookUnregister);
17239
+ const previous = runtimes.get(api);
17240
+ if (previous) {
17241
+ previous.state.hookUnregister = releaseHandle(previous.state.hookUnregister);
17242
+ previous.state.postHookUnregister = releaseHandle(previous.state.postHookUnregister);
17243
+ }
17239
17244
  const cfg = readConfig42(api.config.extensions?.["secret-scanner"]);
17240
17245
  PATTERNS3 = [...BASE_PATTERNS];
17241
17246
  for (const cp of cfg.customPatterns) {
@@ -17245,12 +17250,21 @@ var plugin46 = {
17245
17250
  }
17246
17251
  }
17247
17252
  COMBINED_REGEX = buildCombinedRegex(PATTERNS3);
17253
+ const runtime = {
17254
+ state: createState2(),
17255
+ patterns: PATTERNS3,
17256
+ combinedRegex: COMBINED_REGEX,
17257
+ groupIndexes: [...GROUP_INDEX_OF_PATTERN]
17258
+ };
17259
+ runtimes.set(api, runtime);
17260
+ latestRuntime = runtime;
17261
+ const { state: state59 } = runtime;
17248
17262
  const log = {
17249
17263
  warn: (msg, ...rest) => api.log.warn(msg, ...rest),
17250
17264
  info: (msg, ...rest) => api.log.info(msg, ...rest)
17251
17265
  };
17252
- const hook = buildHook(cfg, log);
17253
- state44.hookUnregister = api.registerHook("PreToolUse", cfg.matcher, hook, {
17266
+ const hook = buildHook(cfg, log, runtime);
17267
+ state59.hookUnregister = api.registerHook("PreToolUse", cfg.matcher, hook, {
17254
17268
  name: "secret-scanner",
17255
17269
  // Redaction rewrites arguments; block/allow modes must inspect the final
17256
17270
  // result after every mutator has run so a later rewrite cannot smuggle a
@@ -17259,8 +17273,8 @@ var plugin46 = {
17259
17273
  failurePolicy: "closed",
17260
17274
  policy: true
17261
17275
  });
17262
- const postHook = buildPostHook(cfg, log);
17263
- state44.postHookUnregister = api.registerHook("PostToolUse", cfg.postToolUseMatcher, postHook);
17276
+ const postHook = buildPostHook(cfg, log, runtime);
17277
+ state59.postHookUnregister = api.registerHook("PostToolUse", cfg.postToolUseMatcher, postHook);
17264
17278
  api.tools.register({
17265
17279
  name: "secret_scanner_status",
17266
17280
  description: "Reports the current secret-scanner state: pattern count, last block (if any), and per-mode invocation counters.",
@@ -17268,6 +17282,7 @@ var plugin46 = {
17268
17282
  permission: "auto",
17269
17283
  mutating: false,
17270
17284
  async execute() {
17285
+ activateRuntime(runtime);
17271
17286
  return {
17272
17287
  ok: true,
17273
17288
  enabled: cfg.enabled,
@@ -17277,13 +17292,13 @@ var plugin46 = {
17277
17292
  patternCount: PATTERNS3.length,
17278
17293
  patternTypes: PATTERNS3.map((p) => p.type),
17279
17294
  counters: {
17280
- block: state44.blockCount,
17281
- redact: state44.redactCount,
17282
- allow: state44.allowCount,
17283
- leak: state44.leakCount
17295
+ block: state59.blockCount,
17296
+ redact: state59.redactCount,
17297
+ allow: state59.allowCount,
17298
+ leak: state59.leakCount
17284
17299
  },
17285
- lastBlock: state44.lastBlock,
17286
- lastLeak: state44.lastLeak
17300
+ lastBlock: state59.lastBlock,
17301
+ lastLeak: state59.lastLeak
17287
17302
  };
17288
17303
  }
17289
17304
  });
@@ -17300,6 +17315,7 @@ var plugin46 = {
17300
17315
  permission: "auto",
17301
17316
  mutating: false,
17302
17317
  async execute(input) {
17318
+ activateRuntime(runtime);
17303
17319
  const text = typeof input["text"] === "string" ? input["text"] : "";
17304
17320
  const matched = findMatches(text);
17305
17321
  return {
@@ -17317,48 +17333,51 @@ var plugin46 = {
17317
17333
  });
17318
17334
  },
17319
17335
  teardown(api) {
17320
- if (state44.hookUnregister) {
17336
+ const runtime = runtimes.get(api);
17337
+ if (!runtime) return;
17338
+ const { state: state59 } = runtime;
17339
+ if (state59.hookUnregister) {
17321
17340
  try {
17322
- state44.hookUnregister();
17341
+ state59.hookUnregister();
17323
17342
  } catch {
17324
17343
  }
17325
- state44.hookUnregister = null;
17344
+ state59.hookUnregister = null;
17326
17345
  }
17327
- if (state44.postHookUnregister) {
17346
+ if (state59.postHookUnregister) {
17328
17347
  try {
17329
- state44.postHookUnregister();
17348
+ state59.postHookUnregister();
17330
17349
  } catch {
17331
17350
  }
17332
- state44.postHookUnregister = null;
17351
+ state59.postHookUnregister = null;
17333
17352
  }
17334
17353
  const finalCounters = {
17335
- block: state44.blockCount,
17336
- redact: state44.redactCount,
17337
- allow: state44.allowCount,
17338
- leak: state44.leakCount
17354
+ block: state59.blockCount,
17355
+ redact: state59.redactCount,
17356
+ allow: state59.allowCount,
17357
+ leak: state59.leakCount
17339
17358
  };
17340
- state44.blockCount = 0;
17341
- state44.redactCount = 0;
17342
- state44.allowCount = 0;
17343
- state44.leakCount = 0;
17344
- state44.lastBlock = null;
17345
- state44.lastLeak = null;
17346
- PATTERNS3 = [...BASE_PATTERNS];
17347
- COMBINED_REGEX = buildCombinedRegex(PATTERNS3);
17359
+ state59.blockCount = 0;
17360
+ state59.redactCount = 0;
17361
+ state59.allowCount = 0;
17362
+ state59.leakCount = 0;
17363
+ state59.lastBlock = null;
17364
+ state59.lastLeak = null;
17365
+ runtimes.delete(api);
17348
17366
  api.log.info("secret-scanner: teardown complete", { counters: finalCounters });
17349
17367
  },
17350
17368
  async health() {
17369
+ const state59 = latestRuntime?.state ?? createState2();
17351
17370
  return {
17352
17371
  ok: true,
17353
- message: state44.lastLeak !== null ? `secret-scanner: last leak at ${state44.lastLeak.when} on ${state44.lastLeak.toolName} (${state44.lastLeak.matchedTypes.join(", ")})` : state44.lastBlock !== null ? `secret-scanner: last block at ${state44.lastBlock.when} on ${state44.lastBlock.toolName} (${state44.lastBlock.matchedTypes.join(", ")})` : `secret-scanner: ${state44.blockCount + state44.redactCount + state44.allowCount + state44.leakCount} invocations, no blocks or leaks`,
17372
+ message: state59.lastLeak !== null ? `secret-scanner: last leak at ${state59.lastLeak.when} on ${state59.lastLeak.toolName} (${state59.lastLeak.matchedTypes.join(", ")})` : state59.lastBlock !== null ? `secret-scanner: last block at ${state59.lastBlock.when} on ${state59.lastBlock.toolName} (${state59.lastBlock.matchedTypes.join(", ")})` : `secret-scanner: ${state59.blockCount + state59.redactCount + state59.allowCount + state59.leakCount} invocations, no blocks or leaks`,
17354
17373
  counters: {
17355
- block: state44.blockCount,
17356
- redact: state44.redactCount,
17357
- allow: state44.allowCount,
17358
- leak: state44.leakCount
17374
+ block: state59.blockCount,
17375
+ redact: state59.redactCount,
17376
+ allow: state59.allowCount,
17377
+ leak: state59.leakCount
17359
17378
  },
17360
- lastBlock: state44.lastBlock,
17361
- lastLeak: state44.lastLeak
17379
+ lastBlock: state59.lastBlock,
17380
+ lastLeak: state59.lastLeak
17362
17381
  };
17363
17382
  }
17364
17383
  };
@@ -17368,7 +17387,7 @@ var secret_scanner_default = plugin46;
17368
17387
  import { readdir as readdir2, readFile as readFile12, stat as stat5 } from "node:fs/promises";
17369
17388
  import { isAbsolute as isAbsolute21, relative as relative21, resolve as resolve21 } from "node:path";
17370
17389
  var API_VERSION30 = "^0.1.10";
17371
- var state45 = {
17390
+ var state43 = {
17372
17391
  scanCount: 0,
17373
17392
  fileScanCount: 0,
17374
17393
  findingCount: 0,
@@ -17575,20 +17594,20 @@ var plugin47 = {
17575
17594
  }
17576
17595
  },
17577
17596
  setup(api) {
17578
- state45.scanCount = 0;
17579
- state45.fileScanCount = 0;
17580
- state45.findingCount = 0;
17581
- state45.hookInvocationCount = 0;
17582
- state45.skippedCount = 0;
17583
- state45.blockedCount = 0;
17584
- state45.lastResult = null;
17585
- state45.knownHotspots.clear();
17586
- if (state45.hookUnregister) {
17597
+ state43.scanCount = 0;
17598
+ state43.fileScanCount = 0;
17599
+ state43.findingCount = 0;
17600
+ state43.hookInvocationCount = 0;
17601
+ state43.skippedCount = 0;
17602
+ state43.blockedCount = 0;
17603
+ state43.lastResult = null;
17604
+ state43.knownHotspots.clear();
17605
+ if (state43.hookUnregister) {
17587
17606
  try {
17588
- state45.hookUnregister();
17607
+ state43.hookUnregister();
17589
17608
  } catch {
17590
17609
  }
17591
- state45.hookUnregister = null;
17610
+ state43.hookUnregister = null;
17592
17611
  }
17593
17612
  const cfg = readConfig43(api.config.extensions?.["security-hotspot-scanner"]);
17594
17613
  const hook = async (input) => {
@@ -17600,25 +17619,25 @@ var plugin47 = {
17600
17619
  if (!withinProject(sourcePath)) return;
17601
17620
  const ext = sourcePath.includes(".") ? sourcePath.slice(sourcePath.lastIndexOf(".")).toLowerCase() : "";
17602
17621
  if (!scanOnChangeSet.has(ext)) {
17603
- state45.skippedCount += 1;
17622
+ state43.skippedCount += 1;
17604
17623
  return;
17605
17624
  }
17606
- state45.hookInvocationCount += 1;
17625
+ state43.hookInvocationCount += 1;
17607
17626
  const result = await scanPath5(sourcePath, cfg);
17608
- state45.scanCount += 1;
17609
- state45.fileScanCount += result.filesScanned;
17627
+ state43.scanCount += 1;
17628
+ state43.fileScanCount += result.filesScanned;
17610
17629
  if (!result.scanned) {
17611
17630
  return;
17612
17631
  }
17613
17632
  const newFindings = result.findings.filter((f) => {
17614
17633
  const key = `${result.path}:${f.type}:${f.line}`;
17615
- if (state45.knownHotspots.has(key)) return false;
17616
- state45.knownHotspots.add(key);
17634
+ if (state43.knownHotspots.has(key)) return false;
17635
+ state43.knownHotspots.add(key);
17617
17636
  return true;
17618
17637
  });
17619
17638
  if (newFindings.length === 0) return;
17620
- state45.findingCount += newFindings.length;
17621
- state45.lastResult = {
17639
+ state43.findingCount += newFindings.length;
17640
+ state43.lastResult = {
17622
17641
  path: result.path,
17623
17642
  findings: newFindings.length,
17624
17643
  durationMs: result.durationMs,
@@ -17633,7 +17652,7 @@ ${lines.join("\n")}` + (result.findings.length >= cfg.maxFindings ? `
17633
17652
  \u2026 and possibly more (showing first ${cfg.maxFindings})` : "") + `
17634
17653
  Review or remove the risky pattern(s).`;
17635
17654
  if (cfg.severity === "block") {
17636
- state45.blockedCount += 1;
17655
+ state43.blockedCount += 1;
17637
17656
  return {
17638
17657
  decision: "block",
17639
17658
  reason: message
@@ -17641,7 +17660,7 @@ Review or remove the risky pattern(s).`;
17641
17660
  }
17642
17661
  return { additionalContext: message };
17643
17662
  };
17644
- state45.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
17663
+ state43.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
17645
17664
  api.tools.register({
17646
17665
  name: "security_hotspot_scan",
17647
17666
  description: "Scan a file or directory for security anti-patterns (eval, Function constructor, innerHTML, SQL concatenation, http URLs, credential logging, variable exec commands).",
@@ -17661,13 +17680,13 @@ Review or remove the risky pattern(s).`;
17661
17680
  async execute(input) {
17662
17681
  if (!cfg.enabled) return { ok: false, error: "security-hotspot-scanner is disabled" };
17663
17682
  const result = await scanPath5(input.path, cfg);
17664
- state45.scanCount += 1;
17665
- state45.fileScanCount += result.filesScanned;
17666
- state45.findingCount += result.findings.length;
17683
+ state43.scanCount += 1;
17684
+ state43.fileScanCount += result.filesScanned;
17685
+ state43.findingCount += result.findings.length;
17667
17686
  if (!result.scanned) {
17668
17687
  return { ok: false, error: result.error, path: input.path };
17669
17688
  }
17670
- state45.lastResult = {
17689
+ state43.lastResult = {
17671
17690
  path: result.path,
17672
17691
  findings: result.findings.length,
17673
17692
  durationMs: result.durationMs,
@@ -17699,14 +17718,14 @@ Review or remove the risky pattern(s).`;
17699
17718
  scanOnChange: cfg.scanOnChange,
17700
17719
  patternTypes: PATTERNS4.map((p) => p.type),
17701
17720
  counters: {
17702
- scans: state45.scanCount,
17703
- filesScanned: state45.fileScanCount,
17704
- findings: state45.findingCount,
17705
- hookInvocations: state45.hookInvocationCount,
17706
- skipped: state45.skippedCount,
17707
- blocked: state45.blockedCount
17721
+ scans: state43.scanCount,
17722
+ filesScanned: state43.fileScanCount,
17723
+ findings: state43.findingCount,
17724
+ hookInvocations: state43.hookInvocationCount,
17725
+ skipped: state43.skippedCount,
17726
+ blocked: state43.blockedCount
17708
17727
  },
17709
- lastResult: state45.lastResult
17728
+ lastResult: state43.lastResult
17710
17729
  };
17711
17730
  }
17712
17731
  });
@@ -17717,44 +17736,44 @@ Review or remove the risky pattern(s).`;
17717
17736
  });
17718
17737
  },
17719
17738
  teardown(api) {
17720
- if (state45.hookUnregister) {
17739
+ if (state43.hookUnregister) {
17721
17740
  try {
17722
- state45.hookUnregister();
17741
+ state43.hookUnregister();
17723
17742
  } catch {
17724
17743
  }
17725
- state45.hookUnregister = null;
17744
+ state43.hookUnregister = null;
17726
17745
  }
17727
17746
  const final = {
17728
- scans: state45.scanCount,
17729
- filesScanned: state45.fileScanCount,
17730
- findings: state45.findingCount,
17731
- hookInvocations: state45.hookInvocationCount,
17732
- skipped: state45.skippedCount,
17733
- blocked: state45.blockedCount
17747
+ scans: state43.scanCount,
17748
+ filesScanned: state43.fileScanCount,
17749
+ findings: state43.findingCount,
17750
+ hookInvocations: state43.hookInvocationCount,
17751
+ skipped: state43.skippedCount,
17752
+ blocked: state43.blockedCount
17734
17753
  };
17735
- state45.scanCount = 0;
17736
- state45.fileScanCount = 0;
17737
- state45.findingCount = 0;
17738
- state45.hookInvocationCount = 0;
17739
- state45.skippedCount = 0;
17740
- state45.blockedCount = 0;
17741
- state45.lastResult = null;
17742
- state45.knownHotspots.clear();
17754
+ state43.scanCount = 0;
17755
+ state43.fileScanCount = 0;
17756
+ state43.findingCount = 0;
17757
+ state43.hookInvocationCount = 0;
17758
+ state43.skippedCount = 0;
17759
+ state43.blockedCount = 0;
17760
+ state43.lastResult = null;
17761
+ state43.knownHotspots.clear();
17743
17762
  api.log.info("security-hotspot-scanner: teardown complete", { final });
17744
17763
  },
17745
17764
  async health() {
17746
17765
  return {
17747
17766
  ok: true,
17748
- message: state45.lastResult ? `security-hotspot-scanner: ${state45.scanCount} scan(s), last scan found ${state45.lastResult.findings} hotspot(s)` : `security-hotspot-scanner: ${state45.scanCount} scan(s), ${state45.findingCount} finding(s)`,
17767
+ message: state43.lastResult ? `security-hotspot-scanner: ${state43.scanCount} scan(s), last scan found ${state43.lastResult.findings} hotspot(s)` : `security-hotspot-scanner: ${state43.scanCount} scan(s), ${state43.findingCount} finding(s)`,
17749
17768
  counters: {
17750
- scans: state45.scanCount,
17751
- filesScanned: state45.fileScanCount,
17752
- findings: state45.findingCount,
17753
- hookInvocations: state45.hookInvocationCount,
17754
- skipped: state45.skippedCount,
17755
- blocked: state45.blockedCount
17756
- },
17757
- lastResult: state45.lastResult
17769
+ scans: state43.scanCount,
17770
+ filesScanned: state43.fileScanCount,
17771
+ findings: state43.findingCount,
17772
+ hookInvocations: state43.hookInvocationCount,
17773
+ skipped: state43.skippedCount,
17774
+ blocked: state43.blockedCount
17775
+ },
17776
+ lastResult: state43.lastResult
17758
17777
  };
17759
17778
  }
17760
17779
  };
@@ -17766,7 +17785,7 @@ import { isAbsolute as isAbsolute22, relative as relative22, resolve as resolve2
17766
17785
  import { DEFAULT_WALK_IGNORE_DIRS } from "@wrongstack/core/utils";
17767
17786
  var API_VERSION31 = "^0.1.10";
17768
17787
  var escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
17769
- var state46 = {
17788
+ var state44 = {
17770
17789
  index: null,
17771
17790
  cachedPath: null,
17772
17791
  fileCount: 0,
@@ -17887,17 +17906,17 @@ function yieldEventLoop() {
17887
17906
  return new Promise((resolve28) => setImmediate(resolve28));
17888
17907
  }
17889
17908
  function addFileToIndex(relPath, content, size, cfg) {
17890
- if (!state46.index || content.includes("\0")) return;
17891
- state46.bytesIndexed += content.length;
17909
+ if (!state44.index || content.includes("\0")) return;
17910
+ state44.bytesIndexed += content.length;
17892
17911
  const lines = content.split(/\r?\n/);
17893
- state46.index.files.set(relPath, { lines, size });
17912
+ state44.index.files.set(relPath, { lines, size });
17894
17913
  for (let i = 0; i < lines.length; i += 1) {
17895
17914
  const terms = tokenize(lines[i], cfg.minTokenLength);
17896
17915
  for (const term of terms) {
17897
- let postings = state46.index.terms.get(term);
17916
+ let postings = state44.index.terms.get(term);
17898
17917
  if (!postings) {
17899
17918
  postings = /* @__PURE__ */ new Map();
17900
- state46.index.terms.set(term, postings);
17919
+ state44.index.terms.set(term, postings);
17901
17920
  }
17902
17921
  let posting = postings.get(relPath);
17903
17922
  if (!posting) {
@@ -17934,8 +17953,8 @@ async function walkDirectory(absPath, cfg, excludes, fileBatch) {
17934
17953
  }
17935
17954
  const root = normalizeSlashes2(process.cwd());
17936
17955
  for (const ent of entries) {
17937
- if (state46.fileCount >= cfg.maxFiles) {
17938
- state46.truncated = true;
17956
+ if (state44.fileCount >= cfg.maxFiles) {
17957
+ state44.truncated = true;
17939
17958
  return;
17940
17959
  }
17941
17960
  const absChild = normalizeSlashes2(resolve22(absPath, ent.name));
@@ -17944,9 +17963,9 @@ async function walkDirectory(absPath, cfg, excludes, fileBatch) {
17944
17963
  if (excludes.some((re) => re.test(relChild))) continue;
17945
17964
  if (ent.isDirectory()) {
17946
17965
  await walkDirectory(absChild, cfg, excludes, fileBatch);
17947
- if (state46.truncated) return;
17966
+ if (state44.truncated) return;
17948
17967
  } else if (ent.isFile()) {
17949
- state46.fileCount += 1;
17968
+ state44.fileCount += 1;
17950
17969
  if (!shouldIndexFile(relChild, cfg)) continue;
17951
17970
  let stats;
17952
17971
  try {
@@ -17958,50 +17977,50 @@ async function walkDirectory(absPath, cfg, excludes, fileBatch) {
17958
17977
  if (fileBatch.length >= INDEX_BATCH_SIZE) {
17959
17978
  await flushFileBatch(fileBatch, cfg);
17960
17979
  }
17961
- if (state46.fileCount % YIELD_EVERY_FILES === 0) {
17980
+ if (state44.fileCount % YIELD_EVERY_FILES === 0) {
17962
17981
  await yieldEventLoop();
17963
17982
  }
17964
17983
  }
17965
17984
  }
17966
17985
  }
17967
17986
  async function buildIndex(rootPath, cfg) {
17968
- state46.index = { terms: /* @__PURE__ */ new Map(), files: /* @__PURE__ */ new Map() };
17969
- state46.cachedPath = rootPath;
17970
- state46.fileCount = 0;
17971
- state46.termCount = 0;
17972
- state46.bytesIndexed = 0;
17973
- state46.truncated = false;
17974
- state46.reindexCount += 1;
17987
+ state44.index = { terms: /* @__PURE__ */ new Map(), files: /* @__PURE__ */ new Map() };
17988
+ state44.cachedPath = rootPath;
17989
+ state44.fileCount = 0;
17990
+ state44.termCount = 0;
17991
+ state44.bytesIndexed = 0;
17992
+ state44.truncated = false;
17993
+ state44.reindexCount += 1;
17975
17994
  const excludes = compileExcludes(cfg.excludePatterns);
17976
17995
  let rootStats;
17977
17996
  try {
17978
17997
  rootStats = await fs2.stat(rootPath);
17979
17998
  } catch {
17980
- state46.termCount = 0;
17999
+ state44.termCount = 0;
17981
18000
  return;
17982
18001
  }
17983
18002
  if (rootStats.isFile()) {
17984
18003
  const relPath = normalizeSlashes2(relative22(normalizeSlashes2(process.cwd()), rootPath));
17985
18004
  await indexFileFromStats(rootPath, relPath === "" ? "." : relPath, rootStats, cfg);
17986
- state46.fileCount = state46.index.files.size;
18005
+ state44.fileCount = state44.index.files.size;
17987
18006
  } else if (rootStats.isDirectory()) {
17988
18007
  const fileBatch = [];
17989
18008
  await walkDirectory(rootPath, cfg, excludes, fileBatch);
17990
18009
  await flushFileBatch(fileBatch, cfg);
17991
18010
  }
17992
- state46.termCount = state46.index.terms.size;
18011
+ state44.termCount = state44.index.terms.size;
17993
18012
  }
17994
18013
  async function ensureIndex(rootPath, cfg) {
17995
- if (state46.index && state46.cachedPath === rootPath) return;
17996
- state46.buildPromise ??= buildIndex(rootPath, cfg).finally(() => {
17997
- state46.buildPromise = null;
18014
+ if (state44.index && state44.cachedPath === rootPath) return;
18015
+ state44.buildPromise ??= buildIndex(rootPath, cfg).finally(() => {
18016
+ state44.buildPromise = null;
17998
18017
  });
17999
- await state46.buildPromise;
18000
- if (!state46.index || state46.cachedPath !== rootPath) {
18001
- state46.buildPromise = buildIndex(rootPath, cfg).finally(() => {
18002
- state46.buildPromise = null;
18018
+ await state44.buildPromise;
18019
+ if (!state44.index || state44.cachedPath !== rootPath) {
18020
+ state44.buildPromise = buildIndex(rootPath, cfg).finally(() => {
18021
+ state44.buildPromise = null;
18003
18022
  });
18004
- await state46.buildPromise;
18023
+ await state44.buildPromise;
18005
18024
  }
18006
18025
  }
18007
18026
  function compareRankedCandidates(a, b) {
@@ -18020,14 +18039,14 @@ function insertTopCandidate(top, candidate, limit) {
18020
18039
  if (top.length > limit) top.pop();
18021
18040
  }
18022
18041
  function runQuery(query, limit, cfg) {
18023
- if (!state46.index) return [];
18042
+ if (!state44.index) return [];
18024
18043
  const rawTokens = tokenize(query, cfg.minTokenLength);
18025
18044
  const uniqueTokens = [...new Set(rawTokens)];
18026
18045
  if (uniqueTokens.length === 0) return [];
18027
18046
  const scores = /* @__PURE__ */ new Map();
18028
18047
  const matchedTerms = /* @__PURE__ */ new Map();
18029
18048
  for (const token of uniqueTokens) {
18030
- const postings = state46.index.terms.get(token);
18049
+ const postings = state44.index.terms.get(token);
18031
18050
  if (!postings) continue;
18032
18051
  for (const [filePath, posting] of postings) {
18033
18052
  scores.set(filePath, (scores.get(filePath) ?? 0) + posting.tf);
@@ -18052,7 +18071,7 @@ function runQuery(query, limit, cfg) {
18052
18071
  );
18053
18072
  }
18054
18073
  return top.map(({ path, score, terms }) => {
18055
- const entry = state46.index.files.get(path);
18074
+ const entry = state44.index.files.get(path);
18056
18075
  const matchedLines = [];
18057
18076
  if (entry) {
18058
18077
  const querySet = new Set(uniqueTokens);
@@ -18132,21 +18151,21 @@ var plugin48 = {
18132
18151
  }
18133
18152
  },
18134
18153
  setup(api) {
18135
- state46.index = null;
18136
- state46.cachedPath = null;
18137
- state46.fileCount = 0;
18138
- state46.termCount = 0;
18139
- state46.bytesIndexed = 0;
18140
- state46.truncated = false;
18141
- state46.queryCount = 0;
18142
- state46.reindexCount = 0;
18143
- state46.buildPromise = null;
18144
- if (state46.hookUnregister) {
18154
+ state44.index = null;
18155
+ state44.cachedPath = null;
18156
+ state44.fileCount = 0;
18157
+ state44.termCount = 0;
18158
+ state44.bytesIndexed = 0;
18159
+ state44.truncated = false;
18160
+ state44.queryCount = 0;
18161
+ state44.reindexCount = 0;
18162
+ state44.buildPromise = null;
18163
+ if (state44.hookUnregister) {
18145
18164
  try {
18146
- state46.hookUnregister();
18165
+ state44.hookUnregister();
18147
18166
  } catch {
18148
18167
  }
18149
- state46.hookUnregister = null;
18168
+ state44.hookUnregister = null;
18150
18169
  }
18151
18170
  const cfg = readConfig44(api.config.extensions?.["semantic-search-indexer"]);
18152
18171
  api.tools.register({
@@ -18188,13 +18207,13 @@ var plugin48 = {
18188
18207
  const limit = typeof input.limit === "number" && input.limit >= 1 ? Math.floor(input.limit) : cfg.defaultLimit;
18189
18208
  const results = runQuery(query, limit, cfg);
18190
18209
  const queryTokens = [...new Set(tokenize(query, cfg.minTokenLength))];
18191
- state46.queryCount += 1;
18210
+ state44.queryCount += 1;
18192
18211
  api.metrics.counter("queries");
18193
18212
  return {
18194
18213
  ok: true,
18195
18214
  query,
18196
18215
  queryTokens,
18197
- indexedPath: state46.cachedPath,
18216
+ indexedPath: state44.cachedPath,
18198
18217
  totalResults: results.length,
18199
18218
  limit,
18200
18219
  results
@@ -18214,14 +18233,14 @@ var plugin48 = {
18214
18233
  return {
18215
18234
  ok: true,
18216
18235
  enabled: cfg.enabled,
18217
- indexedPath: state46.cachedPath,
18218
- fileCount: state46.fileCount,
18219
- termCount: state46.termCount,
18220
- bytesIndexed: state46.bytesIndexed,
18221
- truncated: state46.truncated,
18236
+ indexedPath: state44.cachedPath,
18237
+ fileCount: state44.fileCount,
18238
+ termCount: state44.termCount,
18239
+ bytesIndexed: state44.bytesIndexed,
18240
+ truncated: state44.truncated,
18222
18241
  counters: {
18223
- queries: state46.queryCount,
18224
- reindexes: state46.reindexCount
18242
+ queries: state44.queryCount,
18243
+ reindexes: state44.reindexCount
18225
18244
  }
18226
18245
  };
18227
18246
  }
@@ -18233,40 +18252,40 @@ var plugin48 = {
18233
18252
  });
18234
18253
  },
18235
18254
  teardown(api) {
18236
- if (state46.hookUnregister) {
18255
+ if (state44.hookUnregister) {
18237
18256
  try {
18238
- state46.hookUnregister();
18257
+ state44.hookUnregister();
18239
18258
  } catch {
18240
18259
  }
18241
- state46.hookUnregister = null;
18260
+ state44.hookUnregister = null;
18242
18261
  }
18243
18262
  const final = {
18244
- fileCount: state46.fileCount,
18245
- termCount: state46.termCount,
18246
- queries: state46.queryCount,
18247
- reindexes: state46.reindexCount
18263
+ fileCount: state44.fileCount,
18264
+ termCount: state44.termCount,
18265
+ queries: state44.queryCount,
18266
+ reindexes: state44.reindexCount
18248
18267
  };
18249
- state46.index = null;
18250
- state46.cachedPath = null;
18251
- state46.fileCount = 0;
18252
- state46.termCount = 0;
18253
- state46.bytesIndexed = 0;
18254
- state46.truncated = false;
18255
- state46.queryCount = 0;
18256
- state46.reindexCount = 0;
18257
- state46.buildPromise = null;
18268
+ state44.index = null;
18269
+ state44.cachedPath = null;
18270
+ state44.fileCount = 0;
18271
+ state44.termCount = 0;
18272
+ state44.bytesIndexed = 0;
18273
+ state44.truncated = false;
18274
+ state44.queryCount = 0;
18275
+ state44.reindexCount = 0;
18276
+ state44.buildPromise = null;
18258
18277
  api.log.info("semantic-search-indexer: teardown complete", { final });
18259
18278
  },
18260
18279
  async health() {
18261
18280
  return {
18262
18281
  ok: true,
18263
- message: `semantic-search-indexer: ${state46.fileCount} file(s), ${state46.termCount} term(s), ${state46.queryCount} query(ies)`,
18282
+ message: `semantic-search-indexer: ${state44.fileCount} file(s), ${state44.termCount} term(s), ${state44.queryCount} query(ies)`,
18264
18283
  counters: {
18265
- fileCount: state46.fileCount,
18266
- termCount: state46.termCount,
18267
- bytesIndexed: state46.bytesIndexed,
18268
- queries: state46.queryCount,
18269
- reindexes: state46.reindexCount
18284
+ fileCount: state44.fileCount,
18285
+ termCount: state44.termCount,
18286
+ bytesIndexed: state44.bytesIndexed,
18287
+ queries: state44.queryCount,
18288
+ reindexes: state44.reindexCount
18270
18289
  }
18271
18290
  };
18272
18291
  }
@@ -18288,7 +18307,7 @@ function resolveProjectRoot(rawCwd, root = process.cwd()) {
18288
18307
  if (rel === "" || !rel.startsWith("..") && !isAbsolute23(rel)) return resolved;
18289
18308
  return null;
18290
18309
  }
18291
- var state47 = {
18310
+ var state45 = {
18292
18311
  /** Total invocations across all three tools this session. */
18293
18312
  invocationCount: 0,
18294
18313
  /** Per-tool invocation counts so /diag can show "bumps: 2, current: 5". */
@@ -18487,9 +18506,9 @@ var plugin49 = {
18487
18506
  }
18488
18507
  },
18489
18508
  setup(api) {
18490
- state47.invocationCount = 0;
18491
- state47.perTool = { semver_bump: 0, semver_current: 0, semver_changelog: 0 };
18492
- state47.lastBump = null;
18509
+ state45.invocationCount = 0;
18510
+ state45.perTool = { semver_bump: 0, semver_current: 0, semver_changelog: 0 };
18511
+ state45.lastBump = null;
18493
18512
  const tagPrefix = api.config.extensions?.["semver-bump"]?.["tagPrefix"] ?? "v";
18494
18513
  const autoTag = api.config.extensions?.["semver-bump"]?.["autoTag"] ?? true;
18495
18514
  const VALID_PARTS = ["major", "minor", "patch", "auto"];
@@ -18613,7 +18632,7 @@ var plugin49 = {
18613
18632
  to: newVersion,
18614
18633
  bump: bumpPart
18615
18634
  });
18616
- state47.lastBump = {
18635
+ state45.lastBump = {
18617
18636
  when: (/* @__PURE__ */ new Date()).toISOString(),
18618
18637
  from: currentVersion,
18619
18638
  to: newVersion,
@@ -18649,8 +18668,8 @@ var plugin49 = {
18649
18668
  permission: "confirm",
18650
18669
  mutating: true,
18651
18670
  async execute(input) {
18652
- state47.invocationCount += 1;
18653
- state47.perTool["semver_bump"] = (state47.perTool["semver_bump"] ?? 0) + 1;
18671
+ state45.invocationCount += 1;
18672
+ state45.perTool["semver_bump"] = (state45.perTool["semver_bump"] ?? 0) + 1;
18654
18673
  const cwd = input["cwd"];
18655
18674
  const dryRun = input["dry_run"] ?? false;
18656
18675
  const part = input["part"] ?? defaultPart;
@@ -18727,8 +18746,8 @@ var plugin49 = {
18727
18746
  permission: "auto",
18728
18747
  mutating: false,
18729
18748
  async execute(input) {
18730
- state47.invocationCount += 1;
18731
- state47.perTool["semver_current"] = (state47.perTool["semver_current"] ?? 0) + 1;
18749
+ state45.invocationCount += 1;
18750
+ state45.perTool["semver_current"] = (state45.perTool["semver_current"] ?? 0) + 1;
18732
18751
  const cwdInput = input["cwd"];
18733
18752
  const safeCwd = resolveProjectRoot(cwdInput);
18734
18753
  if (!safeCwd) {
@@ -18775,8 +18794,8 @@ var plugin49 = {
18775
18794
  permission: "auto",
18776
18795
  mutating: false,
18777
18796
  async execute(input) {
18778
- state47.invocationCount += 1;
18779
- state47.perTool["semver_changelog"] = (state47.perTool["semver_changelog"] ?? 0) + 1;
18797
+ state45.invocationCount += 1;
18798
+ state45.perTool["semver_changelog"] = (state45.perTool["semver_changelog"] ?? 0) + 1;
18780
18799
  const from = input["from"];
18781
18800
  const to = input["to"] ?? "HEAD";
18782
18801
  const cwd = input["cwd"];
@@ -18824,11 +18843,11 @@ var plugin49 = {
18824
18843
  api.log.info("semver-bump plugin loaded", { version: "0.1.0", tagPrefix, autoTag });
18825
18844
  },
18826
18845
  teardown(api) {
18827
- const finalTotal = state47.invocationCount;
18828
- const finalPerTool = { ...state47.perTool };
18829
- state47.invocationCount = 0;
18830
- state47.perTool = { semver_bump: 0, semver_current: 0, semver_changelog: 0 };
18831
- state47.lastBump = null;
18846
+ const finalTotal = state45.invocationCount;
18847
+ const finalPerTool = { ...state45.perTool };
18848
+ state45.invocationCount = 0;
18849
+ state45.perTool = { semver_bump: 0, semver_current: 0, semver_changelog: 0 };
18850
+ state45.lastBump = null;
18832
18851
  api.log.info("semver-bump: teardown complete", {
18833
18852
  invocations: finalTotal,
18834
18853
  perTool: finalPerTool
@@ -18837,17 +18856,17 @@ var plugin49 = {
18837
18856
  async health() {
18838
18857
  return {
18839
18858
  ok: true,
18840
- message: state47.lastBump === null ? `semver-bump: ${state47.invocationCount} call(s) this session` : `semver-bump: last bump ${state47.lastBump.from} \u2192 ${state47.lastBump.to} (${state47.lastBump.type}) at ${state47.lastBump.when}`,
18841
- invocationCount: state47.invocationCount,
18842
- perTool: { ...state47.perTool },
18843
- lastBump: state47.lastBump
18859
+ message: state45.lastBump === null ? `semver-bump: ${state45.invocationCount} call(s) this session` : `semver-bump: last bump ${state45.lastBump.from} \u2192 ${state45.lastBump.to} (${state45.lastBump.type}) at ${state45.lastBump.when}`,
18860
+ invocationCount: state45.invocationCount,
18861
+ perTool: { ...state45.perTool },
18862
+ lastBump: state45.lastBump
18844
18863
  };
18845
18864
  }
18846
18865
  };
18847
18866
  var semver_bump_default = plugin49;
18848
18867
 
18849
18868
  // src/session-recap/index.ts
18850
- var state48 = {
18869
+ var state46 = {
18851
18870
  recapsPublished: 0,
18852
18871
  recapsErrored: 0,
18853
18872
  recapsSkipped: 0,
@@ -18884,23 +18903,23 @@ function readConfig45(raw) {
18884
18903
  }
18885
18904
  function touchActivity() {
18886
18905
  const now = (/* @__PURE__ */ new Date()).toISOString();
18887
- if (state48.startedAt === null) state48.startedAt = now;
18888
- state48.lastActivityAt = now;
18906
+ if (state46.startedAt === null) state46.startedAt = now;
18907
+ state46.lastActivityAt = now;
18889
18908
  }
18890
18909
  function bumpModelUsage(model, inputTokens, outputTokens) {
18891
- let m = state48.perModel.get(model);
18910
+ let m = state46.perModel.get(model);
18892
18911
  if (!m) {
18893
18912
  m = { inputTokens: 0, outputTokens: 0, invocations: 0 };
18894
- state48.perModel.set(model, m);
18913
+ state46.perModel.set(model, m);
18895
18914
  }
18896
18915
  m.inputTokens += inputTokens;
18897
18916
  m.outputTokens += outputTokens;
18898
18917
  m.invocations += 1;
18899
- state48.totalInputTokens += inputTokens;
18900
- state48.totalOutputTokens += outputTokens;
18918
+ state46.totalInputTokens += inputTokens;
18919
+ state46.totalOutputTokens += outputTokens;
18901
18920
  }
18902
18921
  function bumpToolCount(name) {
18903
- state48.toolCounts.set(name, (state48.toolCounts.get(name) ?? 0) + 1);
18922
+ state46.toolCounts.set(name, (state46.toolCounts.get(name) ?? 0) + 1);
18904
18923
  }
18905
18924
  function formatDuration(startedAt, lastActivityAt) {
18906
18925
  if (!startedAt) return "0s";
@@ -19024,27 +19043,27 @@ var plugin50 = {
19024
19043
  }
19025
19044
  },
19026
19045
  setup(api) {
19027
- state48.recapsPublished = 0;
19028
- state48.recapsErrored = 0;
19029
- state48.recapsSkipped = 0;
19030
- state48.aiSummariesWritten = 0;
19031
- state48.aiSummaryErrors = 0;
19032
- state48.stopInvocations = 0;
19033
- state48.totalInputTokens = 0;
19034
- state48.totalOutputTokens = 0;
19035
- state48.perModel.clear();
19036
- state48.toolCounts.clear();
19037
- state48.commitCount = 0;
19038
- state48.startedAt = null;
19039
- state48.lastActivityAt = null;
19040
- state48.stopHookUnregister = releaseHandle(state48.stopHookUnregister);
19041
- for (const off of state48.eventUnsubscribers) {
19046
+ state46.recapsPublished = 0;
19047
+ state46.recapsErrored = 0;
19048
+ state46.recapsSkipped = 0;
19049
+ state46.aiSummariesWritten = 0;
19050
+ state46.aiSummaryErrors = 0;
19051
+ state46.stopInvocations = 0;
19052
+ state46.totalInputTokens = 0;
19053
+ state46.totalOutputTokens = 0;
19054
+ state46.perModel.clear();
19055
+ state46.toolCounts.clear();
19056
+ state46.commitCount = 0;
19057
+ state46.startedAt = null;
19058
+ state46.lastActivityAt = null;
19059
+ state46.stopHookUnregister = releaseHandle(state46.stopHookUnregister);
19060
+ for (const off of state46.eventUnsubscribers) {
19042
19061
  try {
19043
19062
  off();
19044
19063
  } catch {
19045
19064
  }
19046
19065
  }
19047
- state48.eventUnsubscribers = [];
19066
+ state46.eventUnsubscribers = [];
19048
19067
  const cfg = readConfig45(api.config.extensions?.["session-recap"]);
19049
19068
  const mailbox = api.mailbox;
19050
19069
  if (api.onEvent) {
@@ -19056,7 +19075,7 @@ var plugin50 = {
19056
19075
  const output = p?.usage?.output ?? 0;
19057
19076
  bumpModelUsage(model, input, output);
19058
19077
  });
19059
- state48.eventUnsubscribers.push(offUsage);
19078
+ state46.eventUnsubscribers.push(offUsage);
19060
19079
  }
19061
19080
  if (api.onPattern) {
19062
19081
  const offTool = api.onPattern("tool.*", (eventName, payload) => {
@@ -19067,21 +19086,21 @@ var plugin50 = {
19067
19086
  if (toolName === "git_autocommit" || toolName.startsWith("git ")) {
19068
19087
  }
19069
19088
  });
19070
- state48.eventUnsubscribers.push(offTool);
19089
+ state46.eventUnsubscribers.push(offTool);
19071
19090
  const offResult = api.onPattern("tool.result", (_event, payload) => {
19072
19091
  const p = payload;
19073
19092
  if (p?.tool === "git_autocommit" && p.isError === false) {
19074
- state48.commitCount += 1;
19093
+ state46.commitCount += 1;
19075
19094
  }
19076
19095
  });
19077
- state48.eventUnsubscribers.push(offResult);
19096
+ state46.eventUnsubscribers.push(offResult);
19078
19097
  }
19079
19098
  const stopHook = async (input) => {
19080
19099
  if (!cfg.enabled) return;
19081
19100
  touchActivity();
19082
- state48.stopInvocations += 1;
19101
+ state46.stopInvocations += 1;
19083
19102
  if (!mailbox) {
19084
- state48.recapsSkipped += 1;
19103
+ state46.recapsSkipped += 1;
19085
19104
  api.log.warn(
19086
19105
  "session-recap: no mailbox available on api \u2014 recap disabled. Add `mailbox` to the setupPlugins() call to enable cross-session summaries."
19087
19106
  );
@@ -19089,18 +19108,18 @@ var plugin50 = {
19089
19108
  }
19090
19109
  const transcriptPath = api.session?.transcriptPath;
19091
19110
  const tailEvents = await readTranscriptTail(transcriptPath, cfg.includeTranscriptTail);
19092
- const duration = formatDuration(state48.startedAt, state48.lastActivityAt);
19111
+ const duration = formatDuration(state46.startedAt, state46.lastActivityAt);
19093
19112
  const recap = {
19094
19113
  session: {
19095
19114
  id: input.sessionId ?? null,
19096
19115
  cwd: input.cwd ?? null,
19097
- startedAt: state48.startedAt,
19098
- endedAt: state48.lastActivityAt,
19116
+ startedAt: state46.startedAt,
19117
+ endedAt: state46.lastActivityAt,
19099
19118
  duration
19100
19119
  },
19101
19120
  tokens: {
19102
- total: { input: state48.totalInputTokens, output: state48.totalOutputTokens },
19103
- perModel: topN(state48.perModel, 10).map(([model, u]) => ({
19121
+ total: { input: state46.totalInputTokens, output: state46.totalOutputTokens },
19122
+ perModel: topN(state46.perModel, 10).map(([model, u]) => ({
19104
19123
  model,
19105
19124
  input: u.inputTokens,
19106
19125
  output: u.outputTokens,
@@ -19108,11 +19127,11 @@ var plugin50 = {
19108
19127
  }))
19109
19128
  },
19110
19129
  tools: {
19111
- totalCalls: [...state48.toolCounts.values()].reduce((a, b) => a + b, 0),
19112
- uniqueTools: state48.toolCounts.size,
19113
- top: topN(state48.toolCounts, 5)
19130
+ totalCalls: [...state46.toolCounts.values()].reduce((a, b) => a + b, 0),
19131
+ uniqueTools: state46.toolCounts.size,
19132
+ top: topN(state46.toolCounts, 5)
19114
19133
  },
19115
- commits: state48.commitCount,
19134
+ commits: state46.commitCount,
19116
19135
  transcriptTail: tailEvents.flatMap((e) => {
19117
19136
  const entry = {};
19118
19137
  if (e.type !== void 0) entry.type = e.type;
@@ -19147,10 +19166,10 @@ Tokens: ${recap.tokens.total.input} in / ${recap.tokens.total.output} out
19147
19166
  const text = result.text.trim();
19148
19167
  if (text) {
19149
19168
  aiSummary = text;
19150
- state48.aiSummariesWritten += 1;
19169
+ state46.aiSummariesWritten += 1;
19151
19170
  }
19152
19171
  } catch {
19153
- state48.aiSummaryErrors += 1;
19172
+ state46.aiSummaryErrors += 1;
19154
19173
  }
19155
19174
  }
19156
19175
  const recapWithSummary = aiSummary ? { summary: aiSummary, ...recap } : recap;
@@ -19171,7 +19190,7 @@ Tokens: ${recap.tokens.total.input} in / ${recap.tokens.total.output} out
19171
19190
  body,
19172
19191
  priority: "low"
19173
19192
  });
19174
- state48.recapsPublished += 1;
19193
+ state46.recapsPublished += 1;
19175
19194
  api.log.info("session-recap: published session summary", {
19176
19195
  messageId: result.id ?? null,
19177
19196
  duration,
@@ -19180,13 +19199,13 @@ Tokens: ${recap.tokens.total.input} in / ${recap.tokens.total.output} out
19180
19199
  tokensOut: recap.tokens.total.output
19181
19200
  });
19182
19201
  } catch (err) {
19183
- state48.recapsErrored += 1;
19202
+ state46.recapsErrored += 1;
19184
19203
  api.log.warn("session-recap: mailbox.send failed", {
19185
19204
  error: err instanceof Error ? err.message : String(err)
19186
19205
  });
19187
19206
  }
19188
19207
  };
19189
- state48.stopHookUnregister = api.registerHook("Stop", void 0, stopHook);
19208
+ state46.stopHookUnregister = api.registerHook("Stop", void 0, stopHook);
19190
19209
  api.tools.register({
19191
19210
  name: "session_recap_status",
19192
19211
  description: "Reports session-recap state: config, accumulated metrics (tokens, tool calls, commits), and last recap status.",
@@ -19205,33 +19224,33 @@ Tokens: ${recap.tokens.total.input} in / ${recap.tokens.total.output} out
19205
19224
  aiSummary: cfg.aiSummary,
19206
19225
  llmAvailable: Boolean(api.llm),
19207
19226
  counters: {
19208
- stopInvocations: state48.stopInvocations,
19209
- recapsPublished: state48.recapsPublished,
19210
- recapsErrored: state48.recapsErrored,
19211
- recapsSkipped: state48.recapsSkipped,
19212
- aiSummariesWritten: state48.aiSummariesWritten,
19213
- aiSummaryErrors: state48.aiSummaryErrors
19227
+ stopInvocations: state46.stopInvocations,
19228
+ recapsPublished: state46.recapsPublished,
19229
+ recapsErrored: state46.recapsErrored,
19230
+ recapsSkipped: state46.recapsSkipped,
19231
+ aiSummariesWritten: state46.aiSummariesWritten,
19232
+ aiSummaryErrors: state46.aiSummaryErrors
19214
19233
  },
19215
19234
  metrics: {
19216
- totalInputTokens: state48.totalInputTokens,
19217
- totalOutputTokens: state48.totalOutputTokens,
19218
- perModel: topN(state48.perModel, 10).map(([model, u]) => ({
19235
+ totalInputTokens: state46.totalInputTokens,
19236
+ totalOutputTokens: state46.totalOutputTokens,
19237
+ perModel: topN(state46.perModel, 10).map(([model, u]) => ({
19219
19238
  model,
19220
19239
  input: u.inputTokens,
19221
19240
  output: u.outputTokens,
19222
19241
  invocations: u.invocations
19223
19242
  })),
19224
19243
  toolCalls: {
19225
- total: [...state48.toolCounts.values()].reduce((a, b) => a + b, 0),
19226
- uniqueTools: state48.toolCounts.size,
19227
- top: topN(state48.toolCounts, 5)
19244
+ total: [...state46.toolCounts.values()].reduce((a, b) => a + b, 0),
19245
+ uniqueTools: state46.toolCounts.size,
19246
+ top: topN(state46.toolCounts, 5)
19228
19247
  },
19229
- commits: state48.commitCount
19248
+ commits: state46.commitCount
19230
19249
  },
19231
19250
  timing: {
19232
- startedAt: state48.startedAt,
19233
- lastActivityAt: state48.lastActivityAt,
19234
- duration: formatDuration(state48.startedAt, state48.lastActivityAt)
19251
+ startedAt: state46.startedAt,
19252
+ lastActivityAt: state46.lastActivityAt,
19253
+ duration: formatDuration(state46.startedAt, state46.lastActivityAt)
19235
19254
  }
19236
19255
  };
19237
19256
  }
@@ -19243,62 +19262,62 @@ Tokens: ${recap.tokens.total.input} in / ${recap.tokens.total.output} out
19243
19262
  });
19244
19263
  },
19245
19264
  teardown(api) {
19246
- if (state48.stopHookUnregister) {
19265
+ if (state46.stopHookUnregister) {
19247
19266
  try {
19248
- state48.stopHookUnregister();
19267
+ state46.stopHookUnregister();
19249
19268
  } catch {
19250
19269
  }
19251
- state48.stopHookUnregister = null;
19270
+ state46.stopHookUnregister = null;
19252
19271
  }
19253
- for (const off of state48.eventUnsubscribers) {
19272
+ for (const off of state46.eventUnsubscribers) {
19254
19273
  try {
19255
19274
  off();
19256
19275
  } catch {
19257
19276
  }
19258
19277
  }
19259
- state48.eventUnsubscribers = [];
19278
+ state46.eventUnsubscribers = [];
19260
19279
  const final = {
19261
- recapsPublished: state48.recapsPublished,
19262
- recapsErrored: state48.recapsErrored,
19263
- recapsSkipped: state48.recapsSkipped,
19264
- aiSummariesWritten: state48.aiSummariesWritten,
19265
- totalInputTokens: state48.totalInputTokens,
19266
- totalOutputTokens: state48.totalOutputTokens,
19267
- toolCalls: [...state48.toolCounts.values()].reduce((a, b) => a + b, 0),
19268
- commits: state48.commitCount
19280
+ recapsPublished: state46.recapsPublished,
19281
+ recapsErrored: state46.recapsErrored,
19282
+ recapsSkipped: state46.recapsSkipped,
19283
+ aiSummariesWritten: state46.aiSummariesWritten,
19284
+ totalInputTokens: state46.totalInputTokens,
19285
+ totalOutputTokens: state46.totalOutputTokens,
19286
+ toolCalls: [...state46.toolCounts.values()].reduce((a, b) => a + b, 0),
19287
+ commits: state46.commitCount
19269
19288
  };
19270
- state48.recapsPublished = 0;
19271
- state48.recapsErrored = 0;
19272
- state48.recapsSkipped = 0;
19273
- state48.aiSummariesWritten = 0;
19274
- state48.aiSummaryErrors = 0;
19275
- state48.stopInvocations = 0;
19276
- state48.totalInputTokens = 0;
19277
- state48.totalOutputTokens = 0;
19278
- state48.perModel.clear();
19279
- state48.toolCounts.clear();
19280
- state48.commitCount = 0;
19281
- state48.startedAt = null;
19282
- state48.lastActivityAt = null;
19289
+ state46.recapsPublished = 0;
19290
+ state46.recapsErrored = 0;
19291
+ state46.recapsSkipped = 0;
19292
+ state46.aiSummariesWritten = 0;
19293
+ state46.aiSummaryErrors = 0;
19294
+ state46.stopInvocations = 0;
19295
+ state46.totalInputTokens = 0;
19296
+ state46.totalOutputTokens = 0;
19297
+ state46.perModel.clear();
19298
+ state46.toolCounts.clear();
19299
+ state46.commitCount = 0;
19300
+ state46.startedAt = null;
19301
+ state46.lastActivityAt = null;
19283
19302
  api.log.info("session-recap: teardown complete", { final });
19284
19303
  },
19285
19304
  async health() {
19286
19305
  return {
19287
19306
  ok: true,
19288
- message: `session-recap: ${state48.stopInvocations} stop(s), ${state48.recapsPublished} recap(s) published (${state48.aiSummariesWritten} with AI summary), ${state48.recapsErrored} error(s), ${state48.totalInputTokens + state48.totalOutputTokens} tokens observed`,
19307
+ message: `session-recap: ${state46.stopInvocations} stop(s), ${state46.recapsPublished} recap(s) published (${state46.aiSummariesWritten} with AI summary), ${state46.recapsErrored} error(s), ${state46.totalInputTokens + state46.totalOutputTokens} tokens observed`,
19289
19308
  counters: {
19290
- stopInvocations: state48.stopInvocations,
19291
- recapsPublished: state48.recapsPublished,
19292
- recapsErrored: state48.recapsErrored,
19293
- recapsSkipped: state48.recapsSkipped,
19294
- aiSummariesWritten: state48.aiSummariesWritten,
19295
- aiSummaryErrors: state48.aiSummaryErrors
19309
+ stopInvocations: state46.stopInvocations,
19310
+ recapsPublished: state46.recapsPublished,
19311
+ recapsErrored: state46.recapsErrored,
19312
+ recapsSkipped: state46.recapsSkipped,
19313
+ aiSummariesWritten: state46.aiSummariesWritten,
19314
+ aiSummaryErrors: state46.aiSummaryErrors
19296
19315
  },
19297
19316
  metrics: {
19298
- totalInputTokens: state48.totalInputTokens,
19299
- totalOutputTokens: state48.totalOutputTokens,
19300
- toolCalls: [...state48.toolCounts.values()].reduce((a, b) => a + b, 0),
19301
- commits: state48.commitCount
19317
+ totalInputTokens: state46.totalInputTokens,
19318
+ totalOutputTokens: state46.totalOutputTokens,
19319
+ toolCalls: [...state46.toolCounts.values()].reduce((a, b) => a + b, 0),
19320
+ commits: state46.commitCount
19302
19321
  }
19303
19322
  };
19304
19323
  }
@@ -19321,7 +19340,7 @@ function withinProject6(p) {
19321
19340
  return true;
19322
19341
  }
19323
19342
  var MAX_PATH_LEN = 4096;
19324
- var state49 = {
19343
+ var state47 = {
19325
19344
  /** Per-session invocation count. */
19326
19345
  invocationCount: 0,
19327
19346
  /** Total issues found across all runs this session (success or fail). */
@@ -19447,9 +19466,9 @@ var plugin51 = {
19447
19466
  }
19448
19467
  },
19449
19468
  setup(api) {
19450
- state49.invocationCount = 0;
19451
- state49.totalIssues = 0;
19452
- state49.lastRun = null;
19469
+ state47.invocationCount = 0;
19470
+ state47.totalIssues = 0;
19471
+ state47.lastRun = null;
19453
19472
  api.tools.register({
19454
19473
  name: "shellcheck",
19455
19474
  description: "Run shellcheck analysis on shell script files. Pass `files` for specific files, or `directory` (optionally with `pattern`) to recursively scan for .sh files. Returns issues with file, line, column, severity, code, and message.",
@@ -19493,7 +19512,7 @@ var plugin51 = {
19493
19512
  const directory = inp.directory ?? ".";
19494
19513
  const pattern = inp.pattern ?? "";
19495
19514
  const severity = inp.severity ?? "warning";
19496
- state49.invocationCount += 1;
19515
+ state47.invocationCount += 1;
19497
19516
  const pathIsSafe = (p) => typeof p === "string" && p.length > 0 && p.length <= MAX_PATH_LEN && withinProject6(p);
19498
19517
  if (!pathIsSafe(directory)) {
19499
19518
  return {
@@ -19522,7 +19541,7 @@ var plugin51 = {
19522
19541
  scannedDirectories = true;
19523
19542
  }
19524
19543
  if (checkFiles.length === 0) {
19525
- state49.lastRun = {
19544
+ state47.lastRun = {
19526
19545
  when: (/* @__PURE__ */ new Date()).toISOString(),
19527
19546
  filesChecked: 0,
19528
19547
  issues: 0,
@@ -19557,8 +19576,8 @@ var plugin51 = {
19557
19576
  const styleCount = issues.filter((i) => i.level === "style").length;
19558
19577
  api.metrics.counter("issues_found", issues.length, { severity });
19559
19578
  api.metrics.histogram("issues_per_file", issues.length / Math.max(checkFiles.length, 1));
19560
- state49.totalIssues += issues.length;
19561
- state49.lastRun = {
19579
+ state47.totalIssues += issues.length;
19580
+ state47.lastRun = {
19562
19581
  when: (/* @__PURE__ */ new Date()).toISOString(),
19563
19582
  filesChecked: checkFiles.length,
19564
19583
  issues: issues.length,
@@ -19586,11 +19605,11 @@ var plugin51 = {
19586
19605
  api.log.info("shell-check plugin loaded", { version: "0.2.0" });
19587
19606
  },
19588
19607
  teardown(api) {
19589
- const finalInvocations = state49.invocationCount;
19590
- const finalIssues = state49.totalIssues;
19591
- state49.invocationCount = 0;
19592
- state49.totalIssues = 0;
19593
- state49.lastRun = null;
19608
+ const finalInvocations = state47.invocationCount;
19609
+ const finalIssues = state47.totalIssues;
19610
+ state47.invocationCount = 0;
19611
+ state47.totalIssues = 0;
19612
+ state47.lastRun = null;
19594
19613
  api.log.info("shell-check: teardown complete", {
19595
19614
  invocations: finalInvocations,
19596
19615
  totalIssues: finalIssues
@@ -19599,10 +19618,10 @@ var plugin51 = {
19599
19618
  async health() {
19600
19619
  return {
19601
19620
  ok: true,
19602
- message: state49.lastRun === null ? `shell-check: ${state49.invocationCount} run(s) this session` : `shell-check: last run checked ${state49.lastRun.filesChecked} file(s), ${state49.lastRun.issues} issue(s) at ${state49.lastRun.when}`,
19603
- invocationCount: state49.invocationCount,
19604
- totalIssues: state49.totalIssues,
19605
- lastRun: state49.lastRun
19621
+ message: state47.lastRun === null ? `shell-check: ${state47.invocationCount} run(s) this session` : `shell-check: last run checked ${state47.lastRun.filesChecked} file(s), ${state47.lastRun.issues} issue(s) at ${state47.lastRun.when}`,
19622
+ invocationCount: state47.invocationCount,
19623
+ totalIssues: state47.totalIssues,
19624
+ lastRun: state47.lastRun
19606
19625
  };
19607
19626
  }
19608
19627
  };
@@ -19612,7 +19631,7 @@ var shell_check_default = plugin51;
19612
19631
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync2 } from "node:fs";
19613
19632
  import { extname as extname6, isAbsolute as isAbsolute25, relative as relative25, resolve as resolve25 } from "node:path";
19614
19633
  var API_VERSION34 = "^0.1.10";
19615
- var state50 = {
19634
+ var state48 = {
19616
19635
  renameCount: 0,
19617
19636
  replacementCount: 0,
19618
19637
  errorCount: 0
@@ -19684,9 +19703,9 @@ var plugin52 = {
19684
19703
  }
19685
19704
  },
19686
19705
  setup(api) {
19687
- state50.renameCount = 0;
19688
- state50.replacementCount = 0;
19689
- state50.errorCount = 0;
19706
+ state48.renameCount = 0;
19707
+ state48.replacementCount = 0;
19708
+ state48.errorCount = 0;
19690
19709
  const cfg = readConfig46(api.config.extensions?.["smart-rename"]);
19691
19710
  api.tools.register({
19692
19711
  name: "smart_rename",
@@ -19740,17 +19759,17 @@ var plugin52 = {
19740
19759
  try {
19741
19760
  content = readFileSync13(resolved, "utf-8");
19742
19761
  } catch (err) {
19743
- state50.errorCount += 1;
19762
+ state48.errorCount += 1;
19744
19763
  return { ok: false, error: String(err) };
19745
19764
  }
19746
19765
  const { preview, replacements } = renameInContent(content, oldName, newName);
19747
- state50.renameCount += 1;
19748
- state50.replacementCount += replacements;
19766
+ state48.renameCount += 1;
19767
+ state48.replacementCount += replacements;
19749
19768
  if (input.apply) {
19750
19769
  try {
19751
19770
  writeFileSync2(resolved, preview, "utf-8");
19752
19771
  } catch (err) {
19753
- state50.errorCount += 1;
19772
+ state48.errorCount += 1;
19754
19773
  return { ok: false, error: String(err) };
19755
19774
  }
19756
19775
  }
@@ -19770,23 +19789,23 @@ var plugin52 = {
19770
19789
  },
19771
19790
  teardown(api) {
19772
19791
  const final = {
19773
- renames: state50.renameCount,
19774
- replacements: state50.replacementCount,
19775
- errors: state50.errorCount
19792
+ renames: state48.renameCount,
19793
+ replacements: state48.replacementCount,
19794
+ errors: state48.errorCount
19776
19795
  };
19777
- state50.renameCount = 0;
19778
- state50.replacementCount = 0;
19779
- state50.errorCount = 0;
19796
+ state48.renameCount = 0;
19797
+ state48.replacementCount = 0;
19798
+ state48.errorCount = 0;
19780
19799
  api.log.info("smart-rename: teardown complete", { final });
19781
19800
  },
19782
19801
  async health() {
19783
19802
  return {
19784
- ok: state50.errorCount === 0,
19785
- message: state50.errorCount ? `smart-rename: ${state50.errorCount} error(s)` : `smart-rename: ${state50.renameCount} rename(s), ${state50.replacementCount} replacement(s)`,
19803
+ ok: state48.errorCount === 0,
19804
+ message: state48.errorCount ? `smart-rename: ${state48.errorCount} error(s)` : `smart-rename: ${state48.renameCount} rename(s), ${state48.replacementCount} replacement(s)`,
19786
19805
  counters: {
19787
- renames: state50.renameCount,
19788
- replacements: state50.replacementCount,
19789
- errors: state50.errorCount
19806
+ renames: state48.renameCount,
19807
+ replacements: state48.replacementCount,
19808
+ errors: state48.errorCount
19790
19809
  }
19791
19810
  };
19792
19811
  }
@@ -19959,7 +19978,7 @@ var PLUGIN_NAMES = Object.freeze(
19959
19978
  );
19960
19979
 
19961
19980
  // src/spec-linker/index.ts
19962
- var state51 = {
19981
+ var state49 = {
19963
19982
  postInvocations: 0,
19964
19983
  preInvocations: 0,
19965
19984
  unlinkedCount: 0,
@@ -20118,15 +20137,15 @@ var plugin53 = {
20118
20137
  }
20119
20138
  },
20120
20139
  setup(api) {
20121
- state51.postInvocations = 0;
20122
- state51.preInvocations = 0;
20123
- state51.unlinkedCount = 0;
20124
- state51.cleanCount = 0;
20125
- state51.skippedNonMd = 0;
20126
- state51.readErrorCount = 0;
20127
- state51.autoFixApplied = 0;
20128
- state51.postHookUnregister = releaseHandle(state51.postHookUnregister);
20129
- state51.preHookUnregister = releaseHandle(state51.preHookUnregister);
20140
+ state49.postInvocations = 0;
20141
+ state49.preInvocations = 0;
20142
+ state49.unlinkedCount = 0;
20143
+ state49.cleanCount = 0;
20144
+ state49.skippedNonMd = 0;
20145
+ state49.readErrorCount = 0;
20146
+ state49.autoFixApplied = 0;
20147
+ state49.postHookUnregister = releaseHandle(state49.postHookUnregister);
20148
+ state49.preHookUnregister = releaseHandle(state49.preHookUnregister);
20130
20149
  const cfg = readConfig47(api.config.extensions?.["spec-linker"]);
20131
20150
  const postHook = async (input) => {
20132
20151
  if (!cfg.enabled) return;
@@ -20137,25 +20156,25 @@ var plugin53 = {
20137
20156
  const filePath = inp.path;
20138
20157
  if (!filePath || typeof filePath !== "string") return;
20139
20158
  if (!fileMatchesGlobs(filePath, cfg.fileGlobs)) {
20140
- state51.skippedNonMd += 1;
20159
+ state49.skippedNonMd += 1;
20141
20160
  return;
20142
20161
  }
20143
- state51.postInvocations += 1;
20162
+ state49.postInvocations += 1;
20144
20163
  let content;
20145
20164
  try {
20146
20165
  const stat8 = await fs3.stat(filePath);
20147
20166
  if (!stat8.isFile()) return;
20148
20167
  content = await fs3.readFile(filePath, "utf-8");
20149
20168
  } catch {
20150
- state51.readErrorCount += 1;
20169
+ state49.readErrorCount += 1;
20151
20170
  return;
20152
20171
  }
20153
20172
  const unlinked = findUnlinkedReferences(content.split("\n"), [...PLUGIN_NAMES]);
20154
20173
  if (unlinked.length === 0) {
20155
- state51.cleanCount += 1;
20174
+ state49.cleanCount += 1;
20156
20175
  return;
20157
20176
  }
20158
- state51.unlinkedCount += 1;
20177
+ state49.unlinkedCount += 1;
20159
20178
  const limited = unlinked.slice(0, cfg.maxReferences);
20160
20179
  const overflow = unlinked.length - limited.length;
20161
20180
  const lines = limited.map(
@@ -20169,7 +20188,7 @@ var plugin53 = {
20169
20188
  ${lines}${overflowNote}`
20170
20189
  };
20171
20190
  };
20172
- state51.postHookUnregister = api.registerHook("PostToolUse", "write|edit", postHook, { background: true });
20191
+ state49.postHookUnregister = api.registerHook("PostToolUse", "write|edit", postHook, { background: true });
20173
20192
  if (cfg.autoFix) {
20174
20193
  const preHook = async (input) => {
20175
20194
  if (!cfg.enabled) return;
@@ -20179,10 +20198,10 @@ ${lines}${overflowNote}`
20179
20198
  if (!filePath || typeof filePath !== "string") return;
20180
20199
  if (!fileMatchesGlobs(filePath, cfg.fileGlobs)) return;
20181
20200
  if (typeof inp.content !== "string" || inp.content.length === 0) return;
20182
- state51.preInvocations += 1;
20201
+ state49.preInvocations += 1;
20183
20202
  const fixed = wrapUnlinkedReferences(inp.content);
20184
20203
  if (fixed === inp.content) return;
20185
- state51.autoFixApplied += 1;
20204
+ state49.autoFixApplied += 1;
20186
20205
  return {
20187
20206
  decision: "allow",
20188
20207
  modifiedInput: { ...inp, content: fixed, path: filePath },
@@ -20190,7 +20209,7 @@ ${lines}${overflowNote}`
20190
20209
  \u{1F517} spec-linker (autoFix): wrapped unlinked plugin reference(s) in '${filePath}'.`
20191
20210
  };
20192
20211
  };
20193
- state51.preHookUnregister = api.registerHook("PreToolUse", "write", preHook, {
20212
+ state49.preHookUnregister = api.registerHook("PreToolUse", "write", preHook, {
20194
20213
  name: "spec-linker-autofix",
20195
20214
  stage: "mutate",
20196
20215
  failurePolicy: "open"
@@ -20211,13 +20230,13 @@ ${lines}${overflowNote}`
20211
20230
  maxReferences: cfg.maxReferences,
20212
20231
  autoFix: cfg.autoFix,
20213
20232
  counters: {
20214
- postInvocations: state51.postInvocations,
20215
- preInvocations: state51.preInvocations,
20216
- unlinked: state51.unlinkedCount,
20217
- clean: state51.cleanCount,
20218
- skippedNonMd: state51.skippedNonMd,
20219
- readErrors: state51.readErrorCount,
20220
- autoFixApplied: state51.autoFixApplied
20233
+ postInvocations: state49.postInvocations,
20234
+ preInvocations: state49.preInvocations,
20235
+ unlinked: state49.unlinkedCount,
20236
+ clean: state49.cleanCount,
20237
+ skippedNonMd: state49.skippedNonMd,
20238
+ readErrors: state49.readErrorCount,
20239
+ autoFixApplied: state49.autoFixApplied
20221
20240
  },
20222
20241
  catalogSize: PLUGIN_NAMES.length
20223
20242
  };
@@ -20232,7 +20251,7 @@ ${lines}${overflowNote}`
20232
20251
  });
20233
20252
  },
20234
20253
  teardown(api) {
20235
- for (const off of [state51.postHookUnregister, state51.preHookUnregister]) {
20254
+ for (const off of [state49.postHookUnregister, state49.preHookUnregister]) {
20236
20255
  if (off) {
20237
20256
  try {
20238
20257
  off();
@@ -20240,38 +20259,38 @@ ${lines}${overflowNote}`
20240
20259
  }
20241
20260
  }
20242
20261
  }
20243
- state51.postHookUnregister = null;
20244
- state51.preHookUnregister = null;
20262
+ state49.postHookUnregister = null;
20263
+ state49.preHookUnregister = null;
20245
20264
  const final = {
20246
- postInvocations: state51.postInvocations,
20247
- preInvocations: state51.preInvocations,
20248
- unlinked: state51.unlinkedCount,
20249
- clean: state51.cleanCount,
20250
- skippedNonMd: state51.skippedNonMd,
20251
- readErrors: state51.readErrorCount,
20252
- autoFixApplied: state51.autoFixApplied
20265
+ postInvocations: state49.postInvocations,
20266
+ preInvocations: state49.preInvocations,
20267
+ unlinked: state49.unlinkedCount,
20268
+ clean: state49.cleanCount,
20269
+ skippedNonMd: state49.skippedNonMd,
20270
+ readErrors: state49.readErrorCount,
20271
+ autoFixApplied: state49.autoFixApplied
20253
20272
  };
20254
- state51.postInvocations = 0;
20255
- state51.preInvocations = 0;
20256
- state51.unlinkedCount = 0;
20257
- state51.cleanCount = 0;
20258
- state51.skippedNonMd = 0;
20259
- state51.readErrorCount = 0;
20260
- state51.autoFixApplied = 0;
20273
+ state49.postInvocations = 0;
20274
+ state49.preInvocations = 0;
20275
+ state49.unlinkedCount = 0;
20276
+ state49.cleanCount = 0;
20277
+ state49.skippedNonMd = 0;
20278
+ state49.readErrorCount = 0;
20279
+ state49.autoFixApplied = 0;
20261
20280
  api.log.info("spec-linker: teardown complete", { final });
20262
20281
  },
20263
20282
  async health() {
20264
20283
  return {
20265
20284
  ok: true,
20266
- message: `spec-linker: post=${state51.postInvocations} pre=${state51.preInvocations}, unlinked=${state51.unlinkedCount}, autoFix=${state51.autoFixApplied}, clean=${state51.cleanCount}, non-md=${state51.skippedNonMd}`,
20285
+ message: `spec-linker: post=${state49.postInvocations} pre=${state49.preInvocations}, unlinked=${state49.unlinkedCount}, autoFix=${state49.autoFixApplied}, clean=${state49.cleanCount}, non-md=${state49.skippedNonMd}`,
20267
20286
  counters: {
20268
- postInvocations: state51.postInvocations,
20269
- preInvocations: state51.preInvocations,
20270
- unlinked: state51.unlinkedCount,
20271
- clean: state51.cleanCount,
20272
- skippedNonMd: state51.skippedNonMd,
20273
- readErrors: state51.readErrorCount,
20274
- autoFixApplied: state51.autoFixApplied
20287
+ postInvocations: state49.postInvocations,
20288
+ preInvocations: state49.preInvocations,
20289
+ unlinked: state49.unlinkedCount,
20290
+ clean: state49.cleanCount,
20291
+ skippedNonMd: state49.skippedNonMd,
20292
+ readErrors: state49.readErrorCount,
20293
+ autoFixApplied: state49.autoFixApplied
20275
20294
  }
20276
20295
  };
20277
20296
  }
@@ -20679,7 +20698,7 @@ var template_engine_default = plugin54;
20679
20698
  // src/test-coverage-gate/index.ts
20680
20699
  import { readFileSync as readFileSync14 } from "node:fs";
20681
20700
  var API_VERSION36 = "^0.1.10";
20682
- var state52 = {
20701
+ var state50 = {
20683
20702
  invocationCount: 0,
20684
20703
  runCount: 0,
20685
20704
  passCount: 0,
@@ -20780,15 +20799,15 @@ var plugin55 = {
20780
20799
  }
20781
20800
  },
20782
20801
  setup(api) {
20783
- state52.invocationCount = 0;
20784
- state52.runCount = 0;
20785
- state52.passCount = 0;
20786
- state52.failCount = 0;
20787
- state52.errorCount = 0;
20788
- state52.skippedCount = 0;
20789
- state52.lastOverallPct = null;
20790
- state52.lastResult = null;
20791
- state52.hookUnregister = releaseHandle(state52.hookUnregister);
20802
+ state50.invocationCount = 0;
20803
+ state50.runCount = 0;
20804
+ state50.passCount = 0;
20805
+ state50.failCount = 0;
20806
+ state50.errorCount = 0;
20807
+ state50.skippedCount = 0;
20808
+ state50.lastOverallPct = null;
20809
+ state50.lastResult = null;
20810
+ state50.hookUnregister = releaseHandle(state50.hookUnregister);
20792
20811
  const cfg = readConfig48(api.config.extensions?.["test-coverage-gate"]);
20793
20812
  const hook = (input) => {
20794
20813
  if (!cfg.enabled) return;
@@ -20799,27 +20818,27 @@ var plugin55 = {
20799
20818
  if (!withinProject(sourcePath)) return;
20800
20819
  const ext = sourcePath.includes(".") ? sourcePath.slice(sourcePath.lastIndexOf(".")).toLowerCase() : "";
20801
20820
  if (!runOnChangeSet.has(ext)) {
20802
- state52.skippedCount += 1;
20821
+ state50.skippedCount += 1;
20803
20822
  return;
20804
20823
  }
20805
- state52.invocationCount += 1;
20824
+ state50.invocationCount += 1;
20806
20825
  const summary = readCoverageSummary(cfg.coveragePath);
20807
20826
  if (!summary) {
20808
- state52.errorCount += 1;
20827
+ state50.errorCount += 1;
20809
20828
  return;
20810
20829
  }
20811
20830
  const pct = overallPercent(summary);
20812
20831
  if (pct === null) {
20813
- state52.errorCount += 1;
20832
+ state50.errorCount += 1;
20814
20833
  return;
20815
20834
  }
20816
- state52.runCount += 1;
20817
- const previous = state52.lastOverallPct;
20818
- state52.lastOverallPct = pct;
20835
+ state50.runCount += 1;
20836
+ const previous = state50.lastOverallPct;
20837
+ state50.lastOverallPct = pct;
20819
20838
  const belowThreshold = pct < cfg.threshold;
20820
20839
  const dropped = previous !== null && previous - pct >= cfg.deltaThreshold;
20821
20840
  const passed = !belowThreshold && !dropped;
20822
- state52.lastResult = {
20841
+ state50.lastResult = {
20823
20842
  overallPct: pct,
20824
20843
  previousOverallPct: previous,
20825
20844
  threshold: cfg.threshold,
@@ -20827,10 +20846,10 @@ var plugin55 = {
20827
20846
  when: (/* @__PURE__ */ new Date()).toISOString()
20828
20847
  };
20829
20848
  if (passed) {
20830
- state52.passCount += 1;
20849
+ state50.passCount += 1;
20831
20850
  return;
20832
20851
  }
20833
- state52.failCount += 1;
20852
+ state50.failCount += 1;
20834
20853
  const parts = ["\n\u274C test-coverage-gate:"];
20835
20854
  if (belowThreshold) {
20836
20855
  parts.push(
@@ -20852,7 +20871,7 @@ var plugin55 = {
20852
20871
  }
20853
20872
  return { additionalContext: message };
20854
20873
  };
20855
- state52.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook);
20874
+ state50.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook);
20856
20875
  api.tools.register({
20857
20876
  name: "coverage_gate_status",
20858
20877
  description: "Reports test-coverage-gate state: threshold, mode, last coverage percentage, and counters.",
@@ -20868,16 +20887,16 @@ var plugin55 = {
20868
20887
  threshold: cfg.threshold,
20869
20888
  mode: cfg.mode,
20870
20889
  deltaThreshold: cfg.deltaThreshold,
20871
- lastOverallPct: state52.lastOverallPct,
20890
+ lastOverallPct: state50.lastOverallPct,
20872
20891
  counters: {
20873
- invocations: state52.invocationCount,
20874
- runs: state52.runCount,
20875
- passed: state52.passCount,
20876
- failed: state52.failCount,
20877
- errors: state52.errorCount,
20878
- skipped: state52.skippedCount
20892
+ invocations: state50.invocationCount,
20893
+ runs: state50.runCount,
20894
+ passed: state50.passCount,
20895
+ failed: state50.failCount,
20896
+ errors: state50.errorCount,
20897
+ skipped: state50.skippedCount
20879
20898
  },
20880
- lastResult: state52.lastResult
20899
+ lastResult: state50.lastResult
20881
20900
  };
20882
20901
  }
20883
20902
  });
@@ -20889,44 +20908,44 @@ var plugin55 = {
20889
20908
  });
20890
20909
  },
20891
20910
  teardown(api) {
20892
- if (state52.hookUnregister) {
20911
+ if (state50.hookUnregister) {
20893
20912
  try {
20894
- state52.hookUnregister();
20913
+ state50.hookUnregister();
20895
20914
  } catch {
20896
20915
  }
20897
- state52.hookUnregister = null;
20916
+ state50.hookUnregister = null;
20898
20917
  }
20899
20918
  const final = {
20900
- invocations: state52.invocationCount,
20901
- runs: state52.runCount,
20902
- passed: state52.passCount,
20903
- failed: state52.failCount,
20904
- errors: state52.errorCount,
20905
- skipped: state52.skippedCount
20919
+ invocations: state50.invocationCount,
20920
+ runs: state50.runCount,
20921
+ passed: state50.passCount,
20922
+ failed: state50.failCount,
20923
+ errors: state50.errorCount,
20924
+ skipped: state50.skippedCount
20906
20925
  };
20907
- state52.invocationCount = 0;
20908
- state52.runCount = 0;
20909
- state52.passCount = 0;
20910
- state52.failCount = 0;
20911
- state52.errorCount = 0;
20912
- state52.skippedCount = 0;
20913
- state52.lastOverallPct = null;
20914
- state52.lastResult = null;
20926
+ state50.invocationCount = 0;
20927
+ state50.runCount = 0;
20928
+ state50.passCount = 0;
20929
+ state50.failCount = 0;
20930
+ state50.errorCount = 0;
20931
+ state50.skippedCount = 0;
20932
+ state50.lastOverallPct = null;
20933
+ state50.lastResult = null;
20915
20934
  api.log.info("test-coverage-gate: teardown complete", { final });
20916
20935
  },
20917
20936
  async health() {
20918
20937
  return {
20919
20938
  ok: true,
20920
- message: state52.lastResult ? `test-coverage-gate: ${state52.runCount} run(s), last ${state52.lastResult.passed ? "PASSED" : "FAILED"} (${state52.lastResult.overallPct.toFixed(2)}%)` : `test-coverage-gate: ${state52.invocationCount} invocation(s), ${state52.runCount} run(s)`,
20939
+ message: state50.lastResult ? `test-coverage-gate: ${state50.runCount} run(s), last ${state50.lastResult.passed ? "PASSED" : "FAILED"} (${state50.lastResult.overallPct.toFixed(2)}%)` : `test-coverage-gate: ${state50.invocationCount} invocation(s), ${state50.runCount} run(s)`,
20921
20940
  counters: {
20922
- invocations: state52.invocationCount,
20923
- runs: state52.runCount,
20924
- passed: state52.passCount,
20925
- failed: state52.failCount,
20926
- errors: state52.errorCount,
20927
- skipped: state52.skippedCount
20928
- },
20929
- lastResult: state52.lastResult
20941
+ invocations: state50.invocationCount,
20942
+ runs: state50.runCount,
20943
+ passed: state50.passCount,
20944
+ failed: state50.failCount,
20945
+ errors: state50.errorCount,
20946
+ skipped: state50.skippedCount
20947
+ },
20948
+ lastResult: state50.lastResult
20930
20949
  };
20931
20950
  }
20932
20951
  };
@@ -20938,7 +20957,7 @@ import { readFileSync as readFileSync15 } from "node:fs";
20938
20957
  import { createRequire as createRequire3 } from "node:module";
20939
20958
  import { dirname as dirname8, isAbsolute as isAbsolute27, relative as relative26, resolve as resolve26 } from "node:path";
20940
20959
  var API_VERSION37 = "^0.1.10";
20941
- var state53 = {
20960
+ var state51 = {
20942
20961
  invocationCount: 0,
20943
20962
  runCount: 0,
20944
20963
  errorCount: 0,
@@ -21144,10 +21163,10 @@ var plugin56 = {
21144
21163
  }
21145
21164
  },
21146
21165
  setup(api) {
21147
- state53.invocationCount = 0;
21148
- state53.runCount = 0;
21149
- state53.errorCount = 0;
21150
- state53.lastResult = null;
21166
+ state51.invocationCount = 0;
21167
+ state51.runCount = 0;
21168
+ state51.errorCount = 0;
21169
+ state51.lastResult = null;
21151
21170
  const cfg = readConfig49(api.config.extensions?.["test-flake-detector"]);
21152
21171
  api.tools.register({
21153
21172
  name: "flake_detect",
@@ -21190,16 +21209,16 @@ var plugin56 = {
21190
21209
  error: "Unsupported test command or unsafe testPattern. Use vitest, jest, or mocha through a supported package runner, and keep patterns inside the project."
21191
21210
  };
21192
21211
  }
21193
- state53.invocationCount += 1;
21212
+ state51.invocationCount += 1;
21194
21213
  const start = Date.now();
21195
21214
  const records = /* @__PURE__ */ new Map();
21196
21215
  let runsCompleted = 0;
21197
21216
  const runErrors = [];
21198
21217
  for (let run = 1; run <= requestedRuns; run += 1) {
21199
21218
  const { output, error } = await runOnce(command, cfg.timeoutMs);
21200
- state53.runCount += 1;
21219
+ state51.runCount += 1;
21201
21220
  if (error) {
21202
- state53.errorCount += 1;
21221
+ state51.errorCount += 1;
21203
21222
  runErrors.push(`run ${run}: ${error}`);
21204
21223
  }
21205
21224
  const parsed = parseTestOutput(output);
@@ -21220,7 +21239,7 @@ var plugin56 = {
21220
21239
  const alwaysFailing = all.filter((r) => r.passCount === 0 && r.failCount > 0);
21221
21240
  const alwaysPassing = all.filter((r) => r.passCount > 0 && r.failCount === 0);
21222
21241
  const durationMs = Date.now() - start;
21223
- state53.lastResult = {
21242
+ state51.lastResult = {
21224
21243
  runsRequested: requestedRuns,
21225
21244
  runsCompleted,
21226
21245
  flakyTests,
@@ -21259,11 +21278,11 @@ var plugin56 = {
21259
21278
  maxRuns: cfg.maxRuns,
21260
21279
  timeoutMs: cfg.timeoutMs,
21261
21280
  counters: {
21262
- invocations: state53.invocationCount,
21263
- runs: state53.runCount,
21264
- errors: state53.errorCount
21281
+ invocations: state51.invocationCount,
21282
+ runs: state51.runCount,
21283
+ errors: state51.errorCount
21265
21284
  },
21266
- lastResult: state53.lastResult
21285
+ lastResult: state51.lastResult
21267
21286
  };
21268
21287
  }
21269
21288
  });
@@ -21275,26 +21294,26 @@ var plugin56 = {
21275
21294
  },
21276
21295
  teardown(api) {
21277
21296
  const final = {
21278
- invocations: state53.invocationCount,
21279
- runs: state53.runCount,
21280
- errors: state53.errorCount
21297
+ invocations: state51.invocationCount,
21298
+ runs: state51.runCount,
21299
+ errors: state51.errorCount
21281
21300
  };
21282
- state53.invocationCount = 0;
21283
- state53.runCount = 0;
21284
- state53.errorCount = 0;
21285
- state53.lastResult = null;
21301
+ state51.invocationCount = 0;
21302
+ state51.runCount = 0;
21303
+ state51.errorCount = 0;
21304
+ state51.lastResult = null;
21286
21305
  api.log.info("test-flake-detector: teardown complete", { final });
21287
21306
  },
21288
21307
  async health() {
21289
21308
  return {
21290
21309
  ok: true,
21291
- message: state53.lastResult ? `test-flake-detector: ${state53.runCount} run(s), last detection found ${state53.lastResult.flakyTests.length} flaky test(s)` : `test-flake-detector: ${state53.invocationCount} invocation(s), ${state53.runCount} run(s)`,
21310
+ message: state51.lastResult ? `test-flake-detector: ${state51.runCount} run(s), last detection found ${state51.lastResult.flakyTests.length} flaky test(s)` : `test-flake-detector: ${state51.invocationCount} invocation(s), ${state51.runCount} run(s)`,
21292
21311
  counters: {
21293
- invocations: state53.invocationCount,
21294
- runs: state53.runCount,
21295
- errors: state53.errorCount
21312
+ invocations: state51.invocationCount,
21313
+ runs: state51.runCount,
21314
+ errors: state51.errorCount
21296
21315
  },
21297
- lastResult: state53.lastResult
21316
+ lastResult: state51.lastResult
21298
21317
  };
21299
21318
  }
21300
21319
  };
@@ -21304,7 +21323,7 @@ var test_flake_detector_default = plugin56;
21304
21323
  import { readFileSync as readFileSync16 } from "node:fs";
21305
21324
  import { isAbsolute as isAbsolute28, relative as relative27, resolve as resolve27 } from "node:path";
21306
21325
  var API_VERSION38 = "^0.1.10";
21307
- var state54 = {
21326
+ var state52 = {
21308
21327
  generateCount: 0,
21309
21328
  exportCount: 0,
21310
21329
  errorCount: 0,
@@ -21549,11 +21568,11 @@ var plugin57 = {
21549
21568
  }
21550
21569
  },
21551
21570
  setup(api) {
21552
- state54.generateCount = 0;
21553
- state54.exportCount = 0;
21554
- state54.errorCount = 0;
21555
- state54.llmGenerationCount = 0;
21556
- state54.llmFallbackCount = 0;
21571
+ state52.generateCount = 0;
21572
+ state52.exportCount = 0;
21573
+ state52.errorCount = 0;
21574
+ state52.llmGenerationCount = 0;
21575
+ state52.llmFallbackCount = 0;
21557
21576
  const cfg = readConfig50(api.config.extensions?.["test-generator"]);
21558
21577
  api.tools.register({
21559
21578
  name: "generate_unit_tests",
@@ -21592,15 +21611,15 @@ var plugin57 = {
21592
21611
  };
21593
21612
  }
21594
21613
  const resolved = resolve27(process.cwd(), rawPath);
21595
- state54.generateCount += 1;
21614
+ state52.generateCount += 1;
21596
21615
  let result;
21597
21616
  try {
21598
21617
  result = generateForFile(resolved, cfg);
21599
21618
  } catch (err) {
21600
- state54.errorCount += 1;
21619
+ state52.errorCount += 1;
21601
21620
  return { ok: false, error: String(err) };
21602
21621
  }
21603
- state54.exportCount += result.exports.length;
21622
+ state52.exportCount += result.exports.length;
21604
21623
  const requested = input.use_llm ?? cfg.useLlm;
21605
21624
  const llm = await runOptionalPluginLlm({
21606
21625
  requested,
@@ -21616,8 +21635,8 @@ var plugin57 = {
21616
21635
  },
21617
21636
  parse: parseGeneratedTest
21618
21637
  });
21619
- if (llm.used) state54.llmGenerationCount += 1;
21620
- else if (requested) state54.llmFallbackCount += 1;
21638
+ if (llm.used) state52.llmGenerationCount += 1;
21639
+ else if (requested) state52.llmFallbackCount += 1;
21621
21640
  api.metrics.counter("generations", 1, { framework: cfg.framework });
21622
21641
  api.metrics.counter("exports_detected", result.exports.length);
21623
21642
  if (llm.used) api.metrics.counter("llm_generations", 1);
@@ -21646,29 +21665,29 @@ var plugin57 = {
21646
21665
  },
21647
21666
  teardown(api) {
21648
21667
  const final = {
21649
- generated: state54.generateCount,
21650
- exports: state54.exportCount,
21651
- errors: state54.errorCount,
21652
- llmGenerations: state54.llmGenerationCount,
21653
- llmFallbacks: state54.llmFallbackCount
21668
+ generated: state52.generateCount,
21669
+ exports: state52.exportCount,
21670
+ errors: state52.errorCount,
21671
+ llmGenerations: state52.llmGenerationCount,
21672
+ llmFallbacks: state52.llmFallbackCount
21654
21673
  };
21655
- state54.generateCount = 0;
21656
- state54.exportCount = 0;
21657
- state54.errorCount = 0;
21658
- state54.llmGenerationCount = 0;
21659
- state54.llmFallbackCount = 0;
21674
+ state52.generateCount = 0;
21675
+ state52.exportCount = 0;
21676
+ state52.errorCount = 0;
21677
+ state52.llmGenerationCount = 0;
21678
+ state52.llmFallbackCount = 0;
21660
21679
  api.log.info("test-generator: teardown complete", { final });
21661
21680
  },
21662
21681
  async health() {
21663
21682
  return {
21664
- ok: state54.errorCount === 0,
21665
- message: state54.errorCount ? `test-generator: ${state54.errorCount} error(s)` : `test-generator: ${state54.generateCount} generation(s), ${state54.exportCount} export(s)`,
21683
+ ok: state52.errorCount === 0,
21684
+ message: state52.errorCount ? `test-generator: ${state52.errorCount} error(s)` : `test-generator: ${state52.generateCount} generation(s), ${state52.exportCount} export(s)`,
21666
21685
  counters: {
21667
- generated: state54.generateCount,
21668
- exports: state54.exportCount,
21669
- errors: state54.errorCount,
21670
- llmGenerations: state54.llmGenerationCount,
21671
- llmFallbacks: state54.llmFallbackCount
21686
+ generated: state52.generateCount,
21687
+ exports: state52.exportCount,
21688
+ errors: state52.errorCount,
21689
+ llmGenerations: state52.llmGenerationCount,
21690
+ llmFallbacks: state52.llmFallbackCount
21672
21691
  }
21673
21692
  };
21674
21693
  }
@@ -21690,7 +21709,7 @@ function resolveExec(command, args) {
21690
21709
  return { cmd: resolved, args: [...args], windowsVerbatimArguments: false };
21691
21710
  }
21692
21711
  var API_VERSION39 = "^0.1.10";
21693
- var state55 = {
21712
+ var state53 = {
21694
21713
  invocationCount: 0,
21695
21714
  /** Times a test file was found and tests ran. */
21696
21715
  runCount: 0,
@@ -22001,16 +22020,16 @@ var plugin58 = {
22001
22020
  }
22002
22021
  },
22003
22022
  async setup(api) {
22004
- state55.invocationCount = 0;
22005
- state55.runCount = 0;
22006
- state55.passCount = 0;
22007
- state55.failCount = 0;
22008
- state55.noTestCount = 0;
22009
- state55.errorCount = 0;
22010
- state55.extensionSkippedCount = 0;
22011
- state55.cachedSkipCount = 0;
22012
- state55.hookUnregister = releaseHandle(state55.hookUnregister);
22013
- state55.lastResult = null;
22023
+ state53.invocationCount = 0;
22024
+ state53.runCount = 0;
22025
+ state53.passCount = 0;
22026
+ state53.failCount = 0;
22027
+ state53.noTestCount = 0;
22028
+ state53.errorCount = 0;
22029
+ state53.extensionSkippedCount = 0;
22030
+ state53.cachedSkipCount = 0;
22031
+ state53.hookUnregister = releaseHandle(state53.hookUnregister);
22032
+ state53.lastResult = null;
22014
22033
  lastPassedHash.clear();
22015
22034
  const cfg = readConfig51(api.config.extensions?.["test-runner-gate"]);
22016
22035
  const runner = await detectRunner(cfg.runner);
@@ -22036,19 +22055,19 @@ var plugin58 = {
22036
22055
  const ext = sourcePath.includes(".") ? sourcePath.slice(sourcePath.lastIndexOf(".")).toLowerCase() : "";
22037
22056
  const resolvable = getResolvableExtensions(cfg.testFilePatterns);
22038
22057
  if (ext && !resolvable.has(ext) && !TESTABLE_DEFAULT_EXTS.has(ext)) {
22039
- state55.extensionSkippedCount += 1;
22058
+ state53.extensionSkippedCount += 1;
22040
22059
  api.metrics.counter("extension_skipped");
22041
22060
  return;
22042
22061
  }
22043
22062
  }
22044
- state55.invocationCount += 1;
22063
+ state53.invocationCount += 1;
22045
22064
  if (cfg.enableContentHashCache) {
22046
22065
  const content = input.toolName === "write" ? inp["content"] ?? "" : input.toolName === "edit" ? inp["new_string"] ?? "" : "";
22047
22066
  if (typeof content === "string" && content.length > 0) {
22048
22067
  const hash = pathContentHash(content);
22049
22068
  const last = lastPassedHash.get(sourcePath);
22050
22069
  if (last !== void 0 && last === hash) {
22051
- state55.cachedSkipCount += 1;
22070
+ state53.cachedSkipCount += 1;
22052
22071
  api.metrics.counter("cached_skip");
22053
22072
  return;
22054
22073
  }
@@ -22056,16 +22075,16 @@ var plugin58 = {
22056
22075
  }
22057
22076
  const testFile = await findTestFile(sourcePath, cfg.testFilePatterns);
22058
22077
  if (!testFile) {
22059
- state55.noTestCount += 1;
22078
+ state53.noTestCount += 1;
22060
22079
  return;
22061
22080
  }
22062
22081
  const result = await runTests(testFile, runner, cfg.command, cfg.timeoutMs);
22063
22082
  if (!result) {
22064
- state55.errorCount += 1;
22083
+ state53.errorCount += 1;
22065
22084
  return;
22066
22085
  }
22067
- state55.runCount += 1;
22068
- state55.lastResult = {
22086
+ state53.runCount += 1;
22087
+ state53.lastResult = {
22069
22088
  sourcePath,
22070
22089
  testPath: testFile,
22071
22090
  passed: result.passed,
@@ -22074,7 +22093,7 @@ var plugin58 = {
22074
22093
  when: (/* @__PURE__ */ new Date()).toISOString()
22075
22094
  };
22076
22095
  if (result.passed) {
22077
- state55.passCount += 1;
22096
+ state53.passCount += 1;
22078
22097
  if (cfg.enableContentHashCache) {
22079
22098
  const content = input.toolName === "write" ? inp["content"] ?? "" : input.toolName === "edit" ? inp["new_string"] ?? "" : "";
22080
22099
  if (typeof content === "string" && content.length > 0) {
@@ -22087,7 +22106,7 @@ var plugin58 = {
22087
22106
  \u2705 test-runner-gate: ${result.testCount} test(s) passed for ${testFile} (${result.duration}). Source: ${sourcePath}.`
22088
22107
  };
22089
22108
  }
22090
- state55.failCount += 1;
22109
+ state53.failCount += 1;
22091
22110
  const failureList = result.failures.length > 0 ? "\n" + result.failures.map((f) => ` \u274C ${f}`).join("\n") : "";
22092
22111
  const truncated = result.failCount > 5 ? `
22093
22112
  \u2026 and ${result.failCount - 5} more failure(s)` : "";
@@ -22100,7 +22119,7 @@ var plugin58 = {
22100
22119
  Fix the failing tests or revert the change if it broke something.`
22101
22120
  };
22102
22121
  };
22103
- state55.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
22122
+ state53.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
22104
22123
  api.tools.register({
22105
22124
  name: "test_gate_status",
22106
22125
  description: "Reports test-runner-gate state: command, patterns, and per-session pass/fail/error/no-test counters.",
@@ -22118,16 +22137,16 @@ Fix the failing tests or revert the change if it broke something.`
22118
22137
  testFilePatterns: cfg.testFilePatterns,
22119
22138
  injectOnPass: cfg.injectOnPass,
22120
22139
  counters: {
22121
- invocations: state55.invocationCount,
22122
- runs: state55.runCount,
22123
- passed: state55.passCount,
22124
- failed: state55.failCount,
22125
- noTest: state55.noTestCount,
22126
- errors: state55.errorCount,
22127
- extensionSkipped: state55.extensionSkippedCount,
22128
- cachedSkips: state55.cachedSkipCount
22140
+ invocations: state53.invocationCount,
22141
+ runs: state53.runCount,
22142
+ passed: state53.passCount,
22143
+ failed: state53.failCount,
22144
+ noTest: state53.noTestCount,
22145
+ errors: state53.errorCount,
22146
+ extensionSkipped: state53.extensionSkippedCount,
22147
+ cachedSkips: state53.cachedSkipCount
22129
22148
  },
22130
- lastResult: state55.lastResult
22149
+ lastResult: state53.lastResult
22131
22150
  };
22132
22151
  }
22133
22152
  });
@@ -22138,57 +22157,57 @@ Fix the failing tests or revert the change if it broke something.`
22138
22157
  });
22139
22158
  },
22140
22159
  teardown(api) {
22141
- if (state55.hookUnregister) {
22160
+ if (state53.hookUnregister) {
22142
22161
  try {
22143
- state55.hookUnregister();
22162
+ state53.hookUnregister();
22144
22163
  } catch {
22145
22164
  }
22146
- state55.hookUnregister = null;
22165
+ state53.hookUnregister = null;
22147
22166
  }
22148
22167
  const final = {
22149
- invocations: state55.invocationCount,
22150
- runs: state55.runCount,
22151
- passed: state55.passCount,
22152
- failed: state55.failCount,
22153
- noTest: state55.noTestCount,
22154
- errors: state55.errorCount,
22155
- extensionSkipped: state55.extensionSkippedCount,
22156
- cachedSkips: state55.cachedSkipCount
22168
+ invocations: state53.invocationCount,
22169
+ runs: state53.runCount,
22170
+ passed: state53.passCount,
22171
+ failed: state53.failCount,
22172
+ noTest: state53.noTestCount,
22173
+ errors: state53.errorCount,
22174
+ extensionSkipped: state53.extensionSkippedCount,
22175
+ cachedSkips: state53.cachedSkipCount
22157
22176
  };
22158
- state55.invocationCount = 0;
22159
- state55.runCount = 0;
22160
- state55.passCount = 0;
22161
- state55.failCount = 0;
22162
- state55.noTestCount = 0;
22163
- state55.errorCount = 0;
22164
- state55.extensionSkippedCount = 0;
22165
- state55.cachedSkipCount = 0;
22166
- state55.lastResult = null;
22177
+ state53.invocationCount = 0;
22178
+ state53.runCount = 0;
22179
+ state53.passCount = 0;
22180
+ state53.failCount = 0;
22181
+ state53.noTestCount = 0;
22182
+ state53.errorCount = 0;
22183
+ state53.extensionSkippedCount = 0;
22184
+ state53.cachedSkipCount = 0;
22185
+ state53.lastResult = null;
22167
22186
  lastPassedHash.clear();
22168
22187
  api.log.info("test-runner-gate: teardown complete", { final });
22169
22188
  },
22170
22189
  async health() {
22171
22190
  return {
22172
22191
  ok: true,
22173
- message: state55.lastResult === null ? `test-runner-gate: ${state55.invocationCount} invocation(s), ${state55.runCount} test run(s)` : state55.lastResult.passed ? `test-runner-gate: last run PASSED (${state55.lastResult.testCount} tests) on ${state55.lastResult.testPath}` : `test-runner-gate: last run FAILED (${state55.lastResult.testCount} tests) on ${state55.lastResult.testPath} at ${state55.lastResult.when}`,
22192
+ message: state53.lastResult === null ? `test-runner-gate: ${state53.invocationCount} invocation(s), ${state53.runCount} test run(s)` : state53.lastResult.passed ? `test-runner-gate: last run PASSED (${state53.lastResult.testCount} tests) on ${state53.lastResult.testPath}` : `test-runner-gate: last run FAILED (${state53.lastResult.testCount} tests) on ${state53.lastResult.testPath} at ${state53.lastResult.when}`,
22174
22193
  counters: {
22175
- invocations: state55.invocationCount,
22176
- runs: state55.runCount,
22177
- passed: state55.passCount,
22178
- failed: state55.failCount,
22179
- noTest: state55.noTestCount,
22180
- errors: state55.errorCount,
22181
- extensionSkipped: state55.extensionSkippedCount,
22182
- cachedSkips: state55.cachedSkipCount
22183
- },
22184
- lastResult: state55.lastResult
22194
+ invocations: state53.invocationCount,
22195
+ runs: state53.runCount,
22196
+ passed: state53.passCount,
22197
+ failed: state53.failCount,
22198
+ noTest: state53.noTestCount,
22199
+ errors: state53.errorCount,
22200
+ extensionSkipped: state53.extensionSkippedCount,
22201
+ cachedSkips: state53.cachedSkipCount
22202
+ },
22203
+ lastResult: state53.lastResult
22185
22204
  };
22186
22205
  }
22187
22206
  };
22188
22207
  var test_runner_gate_default = plugin58;
22189
22208
 
22190
22209
  // src/todo-listener/index.ts
22191
- var state56 = {
22210
+ var state54 = {
22192
22211
  invocationCount: 0,
22193
22212
  sentCount: 0,
22194
22213
  skippedCount: 0,
@@ -22253,23 +22272,23 @@ var plugin59 = {
22253
22272
  }
22254
22273
  },
22255
22274
  setup(api) {
22256
- state56.invocationCount = 0;
22257
- state56.sentCount = 0;
22258
- state56.skippedCount = 0;
22259
- state56.errorCount = 0;
22260
- state56.lastMessageId = null;
22261
- state56.lastPayloadHash = "";
22262
- state56.lastBroadcastAt = 0;
22263
- state56.hookUnregister = releaseHandle(state56.hookUnregister);
22275
+ state54.invocationCount = 0;
22276
+ state54.sentCount = 0;
22277
+ state54.skippedCount = 0;
22278
+ state54.errorCount = 0;
22279
+ state54.lastMessageId = null;
22280
+ state54.lastPayloadHash = "";
22281
+ state54.lastBroadcastAt = 0;
22282
+ state54.hookUnregister = releaseHandle(state54.hookUnregister);
22264
22283
  const cfg = readConfig52(api.config.extensions?.["todo-listener"]);
22265
22284
  const mailbox = api.mailbox;
22266
22285
  const hook = async (input) => {
22267
22286
  if (!cfg.enabled) return;
22268
22287
  if (input.toolName !== "todo") return;
22269
22288
  if (input.toolResult?.isError) return;
22270
- state56.invocationCount += 1;
22289
+ state54.invocationCount += 1;
22271
22290
  if (!mailbox) {
22272
- state56.skippedCount += 1;
22291
+ state54.skippedCount += 1;
22273
22292
  api.log.warn(
22274
22293
  "todo-listener: no mailbox available on api \u2014 broadcasts disabled. Add `mailbox` to the setupPlugins() call to enable cross-agent visibility."
22275
22294
  );
@@ -22288,13 +22307,13 @@ var plugin59 = {
22288
22307
  items: todos.map((t) => ({ id: t.id, status: t.status, content: t.content }))
22289
22308
  };
22290
22309
  const hash = hashTodos(todos);
22291
- if (cfg.broadcastOnChange && hash === state56.lastPayloadHash) {
22292
- state56.skippedCount += 1;
22310
+ if (cfg.broadcastOnChange && hash === state54.lastPayloadHash) {
22311
+ state54.skippedCount += 1;
22293
22312
  return;
22294
22313
  }
22295
22314
  const now = Date.now();
22296
- if (now - state56.lastBroadcastAt < cfg.cooldownMs) {
22297
- state56.skippedCount += 1;
22315
+ if (now - state54.lastBroadcastAt < cfg.cooldownMs) {
22316
+ state54.skippedCount += 1;
22298
22317
  return;
22299
22318
  }
22300
22319
  const subject = `${cfg.subjectPrefix}${inProgress ? `working on '${inProgress.content}'` : `${todos.length} item(s)`}`.slice(
@@ -22313,23 +22332,23 @@ var plugin59 = {
22313
22332
  try {
22314
22333
  const result = await mailbox.send(sendInput);
22315
22334
  const id = result.id ?? null;
22316
- state56.sentCount += 1;
22317
- state56.lastMessageId = id;
22318
- state56.lastPayloadHash = hash;
22319
- state56.lastBroadcastAt = now;
22335
+ state54.sentCount += 1;
22336
+ state54.lastMessageId = id;
22337
+ state54.lastPayloadHash = hash;
22338
+ state54.lastBroadcastAt = now;
22320
22339
  api.log.info(`todo-listener: broadcast todo update`, {
22321
22340
  count: payload.count,
22322
22341
  inProgress: payload.inProgress?.id ?? null,
22323
22342
  messageId: id
22324
22343
  });
22325
22344
  } catch (err) {
22326
- state56.errorCount += 1;
22345
+ state54.errorCount += 1;
22327
22346
  api.log.warn("todo-listener: mailbox.send failed", {
22328
22347
  error: err instanceof Error ? err.message : String(err)
22329
22348
  });
22330
22349
  }
22331
22350
  };
22332
- state56.hookUnregister = api.registerHook("PostToolUse", "todo", hook);
22351
+ state54.hookUnregister = api.registerHook("PostToolUse", "todo", hook);
22333
22352
  api.tools.register({
22334
22353
  name: "todo_listener_status",
22335
22354
  description: "Reports todo-listener state: config + per-session counters (invocations, sent, skipped, errors) and last broadcast id.",
@@ -22346,13 +22365,13 @@ var plugin59 = {
22346
22365
  cooldownMs: cfg.cooldownMs,
22347
22366
  mailboxAvailable: Boolean(mailbox),
22348
22367
  counters: {
22349
- invocations: state56.invocationCount,
22350
- sent: state56.sentCount,
22351
- skipped: state56.skippedCount,
22352
- errors: state56.errorCount
22368
+ invocations: state54.invocationCount,
22369
+ sent: state54.sentCount,
22370
+ skipped: state54.skippedCount,
22371
+ errors: state54.errorCount
22353
22372
  },
22354
- lastMessageId: state56.lastMessageId,
22355
- lastBroadcastAt: state56.lastBroadcastAt > 0 ? new Date(state56.lastBroadcastAt).toISOString() : null
22373
+ lastMessageId: state54.lastMessageId,
22374
+ lastBroadcastAt: state54.lastBroadcastAt > 0 ? new Date(state54.lastBroadcastAt).toISOString() : null
22356
22375
  };
22357
22376
  }
22358
22377
  });
@@ -22363,40 +22382,40 @@ var plugin59 = {
22363
22382
  });
22364
22383
  },
22365
22384
  teardown(api) {
22366
- if (state56.hookUnregister) {
22385
+ if (state54.hookUnregister) {
22367
22386
  try {
22368
- state56.hookUnregister();
22387
+ state54.hookUnregister();
22369
22388
  } catch {
22370
22389
  }
22371
- state56.hookUnregister = null;
22390
+ state54.hookUnregister = null;
22372
22391
  }
22373
22392
  const final = {
22374
- invocations: state56.invocationCount,
22375
- sent: state56.sentCount,
22376
- skipped: state56.skippedCount,
22377
- errors: state56.errorCount
22393
+ invocations: state54.invocationCount,
22394
+ sent: state54.sentCount,
22395
+ skipped: state54.skippedCount,
22396
+ errors: state54.errorCount
22378
22397
  };
22379
- state56.invocationCount = 0;
22380
- state56.sentCount = 0;
22381
- state56.skippedCount = 0;
22382
- state56.errorCount = 0;
22383
- state56.lastMessageId = null;
22384
- state56.lastPayloadHash = "";
22385
- state56.lastBroadcastAt = 0;
22398
+ state54.invocationCount = 0;
22399
+ state54.sentCount = 0;
22400
+ state54.skippedCount = 0;
22401
+ state54.errorCount = 0;
22402
+ state54.lastMessageId = null;
22403
+ state54.lastPayloadHash = "";
22404
+ state54.lastBroadcastAt = 0;
22386
22405
  api.log.info("todo-listener: teardown complete", { final });
22387
22406
  },
22388
22407
  async health() {
22389
- const base = `todo-listener: ${state56.invocationCount} invocation(s), ${state56.sentCount} sent, ${state56.skippedCount} skipped, ${state56.errorCount} error(s)`;
22408
+ const base = `todo-listener: ${state54.invocationCount} invocation(s), ${state54.sentCount} sent, ${state54.skippedCount} skipped, ${state54.errorCount} error(s)`;
22390
22409
  return {
22391
22410
  ok: true,
22392
- message: state56.lastMessageId ? `${base}; last broadcast ${state56.lastMessageId}` : `${base}; no broadcast yet`,
22411
+ message: state54.lastMessageId ? `${base}; last broadcast ${state54.lastMessageId}` : `${base}; no broadcast yet`,
22393
22412
  counters: {
22394
- invocations: state56.invocationCount,
22395
- sent: state56.sentCount,
22396
- skipped: state56.skippedCount,
22397
- errors: state56.errorCount
22413
+ invocations: state54.invocationCount,
22414
+ sent: state54.sentCount,
22415
+ skipped: state54.skippedCount,
22416
+ errors: state54.errorCount
22398
22417
  },
22399
- lastMessageId: state56.lastMessageId
22418
+ lastMessageId: state54.lastMessageId
22400
22419
  };
22401
22420
  }
22402
22421
  };
@@ -22438,7 +22457,7 @@ async function saveFile(filePath, file) {
22438
22457
  await ensureDir3(filePath.replace(/[/\\][^/\\]+$/, ""));
22439
22458
  await atomicWrite3(filePath, JSON.stringify(file, null, 2), { mode: 384 });
22440
22459
  }
22441
- var state57 = {
22460
+ var state55 = {
22442
22461
  filePath: null,
22443
22462
  projectSlug: null,
22444
22463
  file: null,
@@ -22454,23 +22473,23 @@ function nowIso() {
22454
22473
  return (/* @__PURE__ */ new Date()).toISOString();
22455
22474
  }
22456
22475
  function ensureFile() {
22457
- if (!state57.file) {
22458
- state57.file = {
22476
+ if (!state55.file) {
22477
+ state55.file = {
22459
22478
  version: FILE_VERSION,
22460
- projectSlug: state57.projectSlug ?? "unconfigured",
22479
+ projectSlug: state55.projectSlug ?? "unconfigured",
22461
22480
  updatedAt: nowIso(),
22462
22481
  items: []
22463
22482
  };
22464
22483
  }
22465
- return state57.file;
22484
+ return state55.file;
22466
22485
  }
22467
22486
  function recordMutation(op, itemId) {
22468
- state57.lastMutation = { op, itemId, when: nowIso() };
22469
- if (op === "add") state57.addCount += 1;
22470
- else if (op === "complete") state57.completeCount += 1;
22471
- else if (op === "drop") state57.dropCount += 1;
22472
- else if (op === "remove") state57.removeCount += 1;
22473
- else if (op === "pull") state57.pullCount += 1;
22487
+ state55.lastMutation = { op, itemId, when: nowIso() };
22488
+ if (op === "add") state55.addCount += 1;
22489
+ else if (op === "complete") state55.completeCount += 1;
22490
+ else if (op === "drop") state55.dropCount += 1;
22491
+ else if (op === "remove") state55.removeCount += 1;
22492
+ else if (op === "pull") state55.pullCount += 1;
22474
22493
  }
22475
22494
  function findItemIndex(id) {
22476
22495
  return ensureFile().items.findIndex((it) => it.id === id);
@@ -22500,13 +22519,13 @@ var plugin60 = {
22500
22519
  }
22501
22520
  },
22502
22521
  async setup(api) {
22503
- state57.addCount = 0;
22504
- state57.completeCount = 0;
22505
- state57.dropCount = 0;
22506
- state57.removeCount = 0;
22507
- state57.pullCount = 0;
22508
- state57.lastMutation = null;
22509
- state57.file = null;
22522
+ state55.addCount = 0;
22523
+ state55.completeCount = 0;
22524
+ state55.dropCount = 0;
22525
+ state55.removeCount = 0;
22526
+ state55.pullCount = 0;
22527
+ state55.lastMutation = null;
22528
+ state55.file = null;
22510
22529
  const derived = deriveFilePath(api);
22511
22530
  if (derived.filePath === null) {
22512
22531
  api.log.warn(
@@ -22514,13 +22533,13 @@ var plugin60 = {
22514
22533
  );
22515
22534
  return;
22516
22535
  }
22517
- state57.filePath = derived.filePath;
22518
- state57.projectSlug = derived.projectSlug;
22519
- state57.file = await loadFile(state57.filePath);
22520
- if (state57.file === null) {
22521
- state57.file = {
22536
+ state55.filePath = derived.filePath;
22537
+ state55.projectSlug = derived.projectSlug;
22538
+ state55.file = await loadFile(state55.filePath);
22539
+ if (state55.file === null) {
22540
+ state55.file = {
22522
22541
  version: FILE_VERSION,
22523
- projectSlug: state57.projectSlug ?? "tracker",
22542
+ projectSlug: state55.projectSlug ?? "tracker",
22524
22543
  updatedAt: nowIso(),
22525
22544
  items: []
22526
22545
  };
@@ -22544,7 +22563,7 @@ var plugin60 = {
22544
22563
  permission: "auto",
22545
22564
  mutating: false,
22546
22565
  async execute(input) {
22547
- if (state57.filePath === null) return notConfiguredError();
22566
+ if (state55.filePath === null) return notConfiguredError();
22548
22567
  const status = input["status"] ?? "active";
22549
22568
  const priority = input["priority"];
22550
22569
  const tag = input["tag"];
@@ -22592,7 +22611,7 @@ var plugin60 = {
22592
22611
  permission: "auto",
22593
22612
  mutating: true,
22594
22613
  async execute(input) {
22595
- if (state57.filePath === null) return notConfiguredError();
22614
+ if (state55.filePath === null) return notConfiguredError();
22596
22615
  const content = typeof input["content"] === "string" ? input["content"].trim() : "";
22597
22616
  if (!content) {
22598
22617
  return { ok: false, error: "content is required and must be a non-empty string" };
@@ -22617,7 +22636,7 @@ var plugin60 = {
22617
22636
  const file = ensureFile();
22618
22637
  file.items.push(item);
22619
22638
  file.updatedAt = now;
22620
- await saveFile(state57.filePath, file);
22639
+ await saveFile(state55.filePath, file);
22621
22640
  recordMutation("add", item.id);
22622
22641
  api.log.info("todo-tracker: added item", { id: item.id, content });
22623
22642
  try {
@@ -22647,7 +22666,7 @@ var plugin60 = {
22647
22666
  permission: "auto",
22648
22667
  mutating: true,
22649
22668
  async execute(input) {
22650
- if (state57.filePath === null) return notConfiguredError();
22669
+ if (state55.filePath === null) return notConfiguredError();
22651
22670
  const id = typeof input["id"] === "string" ? input["id"] : "";
22652
22671
  if (!id) return { ok: false, error: "id is required" };
22653
22672
  const idx = findItemIndex(id);
@@ -22662,7 +22681,7 @@ var plugin60 = {
22662
22681
  item.updatedAt = now;
22663
22682
  item.completedAt = now;
22664
22683
  file.updatedAt = now;
22665
- await saveFile(state57.filePath, file);
22684
+ await saveFile(state55.filePath, file);
22666
22685
  recordMutation("complete", id);
22667
22686
  api.log.info("todo-tracker: completed item", { id });
22668
22687
  return { ok: true, item };
@@ -22681,7 +22700,7 @@ var plugin60 = {
22681
22700
  permission: "auto",
22682
22701
  mutating: true,
22683
22702
  async execute(input) {
22684
- if (state57.filePath === null) return notConfiguredError();
22703
+ if (state55.filePath === null) return notConfiguredError();
22685
22704
  const id = typeof input["id"] === "string" ? input["id"] : "";
22686
22705
  if (!id) return { ok: false, error: "id is required" };
22687
22706
  const idx = findItemIndex(id);
@@ -22696,7 +22715,7 @@ var plugin60 = {
22696
22715
  item.updatedAt = now;
22697
22716
  item.completedAt = now;
22698
22717
  file.updatedAt = now;
22699
- await saveFile(state57.filePath, file);
22718
+ await saveFile(state55.filePath, file);
22700
22719
  recordMutation("drop", id);
22701
22720
  return { ok: true, item };
22702
22721
  }
@@ -22714,7 +22733,7 @@ var plugin60 = {
22714
22733
  permission: "confirm",
22715
22734
  mutating: true,
22716
22735
  async execute(input) {
22717
- if (state57.filePath === null) return notConfiguredError();
22736
+ if (state55.filePath === null) return notConfiguredError();
22718
22737
  const id = typeof input["id"] === "string" ? input["id"] : "";
22719
22738
  if (!id) return { ok: false, error: "id is required" };
22720
22739
  const idx = findItemIndex(id);
@@ -22722,7 +22741,7 @@ var plugin60 = {
22722
22741
  const file = ensureFile();
22723
22742
  const [removed] = file.items.splice(idx, 1);
22724
22743
  file.updatedAt = nowIso();
22725
- await saveFile(state57.filePath, file);
22744
+ await saveFile(state55.filePath, file);
22726
22745
  recordMutation("remove", id);
22727
22746
  return { ok: true, removed };
22728
22747
  }
@@ -22739,7 +22758,7 @@ var plugin60 = {
22739
22758
  permission: "auto",
22740
22759
  mutating: false,
22741
22760
  async execute(input) {
22742
- if (state57.filePath === null) return notConfiguredError();
22761
+ if (state55.filePath === null) return notConfiguredError();
22743
22762
  const limit = Math.min(Math.max(Number(input["limit"] ?? 50) || 50, 1), 200);
22744
22763
  const file = ensureFile();
22745
22764
  const items = file.items.filter((it) => it.status === "pending" || it.status === "in_progress").slice(0, limit);
@@ -22761,7 +22780,7 @@ var plugin60 = {
22761
22780
  permission: "auto",
22762
22781
  mutating: false,
22763
22782
  async execute() {
22764
- if (state57.filePath === null) return notConfiguredError();
22783
+ if (state55.filePath === null) return notConfiguredError();
22765
22784
  const file = ensureFile();
22766
22785
  const byStatus = {
22767
22786
  pending: 0,
@@ -22772,49 +22791,49 @@ var plugin60 = {
22772
22791
  for (const it of file.items) byStatus[it.status] += 1;
22773
22792
  return {
22774
22793
  ok: true,
22775
- filePath: state57.filePath,
22776
- projectSlug: state57.projectSlug,
22794
+ filePath: state55.filePath,
22795
+ projectSlug: state55.projectSlug,
22777
22796
  updatedAt: file.updatedAt,
22778
22797
  counters: byStatus,
22779
22798
  total: file.items.length,
22780
22799
  session: {
22781
- add: state57.addCount,
22782
- complete: state57.completeCount,
22783
- drop: state57.dropCount,
22784
- remove: state57.removeCount,
22785
- pull: state57.pullCount
22800
+ add: state55.addCount,
22801
+ complete: state55.completeCount,
22802
+ drop: state55.dropCount,
22803
+ remove: state55.removeCount,
22804
+ pull: state55.pullCount
22786
22805
  },
22787
- lastMutation: state57.lastMutation
22806
+ lastMutation: state55.lastMutation
22788
22807
  };
22789
22808
  }
22790
22809
  });
22791
22810
  api.log.info("todo-tracker plugin loaded", {
22792
- filePath: state57.filePath,
22793
- projectSlug: state57.projectSlug,
22794
- initialItemCount: state57.file.items.length
22811
+ filePath: state55.filePath,
22812
+ projectSlug: state55.projectSlug,
22813
+ initialItemCount: state55.file.items.length
22795
22814
  });
22796
22815
  },
22797
22816
  teardown(api) {
22798
22817
  const finalCounts = {
22799
- add: state57.addCount,
22800
- complete: state57.completeCount,
22801
- drop: state57.dropCount,
22802
- remove: state57.removeCount,
22803
- pull: state57.pullCount
22818
+ add: state55.addCount,
22819
+ complete: state55.completeCount,
22820
+ drop: state55.dropCount,
22821
+ remove: state55.removeCount,
22822
+ pull: state55.pullCount
22804
22823
  };
22805
- state57.addCount = 0;
22806
- state57.completeCount = 0;
22807
- state57.dropCount = 0;
22808
- state57.removeCount = 0;
22809
- state57.pullCount = 0;
22810
- state57.lastMutation = null;
22811
- state57.file = null;
22812
- state57.filePath = null;
22813
- state57.projectSlug = null;
22824
+ state55.addCount = 0;
22825
+ state55.completeCount = 0;
22826
+ state55.dropCount = 0;
22827
+ state55.removeCount = 0;
22828
+ state55.pullCount = 0;
22829
+ state55.lastMutation = null;
22830
+ state55.file = null;
22831
+ state55.filePath = null;
22832
+ state55.projectSlug = null;
22814
22833
  api.log.info("todo-tracker: teardown complete", { sessionCounts: finalCounts });
22815
22834
  },
22816
22835
  async health() {
22817
- if (state57.filePath === null) {
22836
+ if (state55.filePath === null) {
22818
22837
  return {
22819
22838
  ok: false,
22820
22839
  message: "todo-tracker: no file path configured \u2014 tools will error"
@@ -22823,18 +22842,18 @@ var plugin60 = {
22823
22842
  const file = ensureFile();
22824
22843
  return {
22825
22844
  ok: true,
22826
- message: `todo-tracker: ${file.items.length} item(s) at ${state57.filePath}`,
22827
- filePath: state57.filePath,
22828
- projectSlug: state57.projectSlug,
22845
+ message: `todo-tracker: ${file.items.length} item(s) at ${state55.filePath}`,
22846
+ filePath: state55.filePath,
22847
+ projectSlug: state55.projectSlug,
22829
22848
  total: file.items.length,
22830
22849
  sessionCounts: {
22831
- add: state57.addCount,
22832
- complete: state57.completeCount,
22833
- drop: state57.dropCount,
22834
- remove: state57.removeCount,
22835
- pull: state57.pullCount
22850
+ add: state55.addCount,
22851
+ complete: state55.completeCount,
22852
+ drop: state55.dropCount,
22853
+ remove: state55.removeCount,
22854
+ pull: state55.pullCount
22836
22855
  },
22837
- lastMutation: state57.lastMutation
22856
+ lastMutation: state55.lastMutation
22838
22857
  };
22839
22858
  }
22840
22859
  };
@@ -22842,7 +22861,7 @@ var todo_tracker_default = plugin60;
22842
22861
 
22843
22862
  // src/token-budget/index.ts
22844
22863
  var API_VERSION40 = "^0.1.10";
22845
- var state58 = {
22864
+ var state56 = {
22846
22865
  totalTokens: 0,
22847
22866
  totalPromptTokens: 0,
22848
22867
  totalCompletionTokens: 0,
@@ -22897,13 +22916,13 @@ function readConfig53(raw) {
22897
22916
  }
22898
22917
  function clearRegistrations2() {
22899
22918
  for (const key of ["hookUnregister", "postHookUnregister"]) {
22900
- const off = state58[key];
22919
+ const off = state56[key];
22901
22920
  if (!off) continue;
22902
22921
  try {
22903
22922
  off();
22904
22923
  } catch {
22905
22924
  }
22906
- state58[key] = null;
22925
+ state56[key] = null;
22907
22926
  }
22908
22927
  }
22909
22928
  var plugin61 = {
@@ -22944,15 +22963,15 @@ var plugin61 = {
22944
22963
  }
22945
22964
  },
22946
22965
  setup(api) {
22947
- state58.totalTokens = 0;
22948
- state58.totalPromptTokens = 0;
22949
- state58.totalCompletionTokens = 0;
22950
- state58.requestCount = 0;
22951
- state58.warningFired = false;
22952
- state58.stopFired = false;
22953
- state58.warnContextInjected = false;
22954
- state58.stopContextInjected = false;
22955
- state58.lastRequest = null;
22966
+ state56.totalTokens = 0;
22967
+ state56.totalPromptTokens = 0;
22968
+ state56.totalCompletionTokens = 0;
22969
+ state56.requestCount = 0;
22970
+ state56.warningFired = false;
22971
+ state56.stopFired = false;
22972
+ state56.warnContextInjected = false;
22973
+ state56.stopContextInjected = false;
22974
+ state56.lastRequest = null;
22956
22975
  clearRegistrations2();
22957
22976
  const cfg = readConfig53(api.config.extensions?.["token-budget"]);
22958
22977
  api.onEvent("provider.response", (payload) => {
@@ -22966,21 +22985,21 @@ var plugin61 = {
22966
22985
  const promptTokens = usage.input ?? 0;
22967
22986
  const completionTokens = usage.output ?? 0;
22968
22987
  const total = promptTokens + completionTokens;
22969
- state58.totalPromptTokens += promptTokens;
22970
- state58.totalCompletionTokens += completionTokens;
22971
- state58.totalTokens += total;
22972
- state58.requestCount += 1;
22973
- state58.lastRequest = {
22988
+ state56.totalPromptTokens += promptTokens;
22989
+ state56.totalCompletionTokens += completionTokens;
22990
+ state56.totalTokens += total;
22991
+ state56.requestCount += 1;
22992
+ state56.lastRequest = {
22974
22993
  model: p?.ctx?.model ?? "unknown",
22975
22994
  prompt: promptTokens,
22976
22995
  completion: completionTokens,
22977
22996
  when: (/* @__PURE__ */ new Date()).toISOString()
22978
22997
  };
22979
22998
  if (cfg.limit <= 0) return;
22980
- const percent = state58.totalTokens / cfg.limit * 100;
22981
- if (!state58.warningFired && percent >= cfg.warnPercent && percent < cfg.stopPercent) {
22982
- state58.warningFired = true;
22983
- const remaining = cfg.limit - state58.totalTokens;
22999
+ const percent = state56.totalTokens / cfg.limit * 100;
23000
+ if (!state56.warningFired && percent >= cfg.warnPercent && percent < cfg.stopPercent) {
23001
+ state56.warningFired = true;
23002
+ const remaining = cfg.limit - state56.totalTokens;
22984
23003
  api.log.info("token-budget: warning threshold reached", {
22985
23004
  percent: Math.round(percent),
22986
23005
  remaining
@@ -22988,45 +23007,45 @@ var plugin61 = {
22988
23007
  api.emitCustom("token-budget:warning", {
22989
23008
  percent: Math.round(percent),
22990
23009
  remaining,
22991
- total: state58.totalTokens,
23010
+ total: state56.totalTokens,
22992
23011
  limit: cfg.limit
22993
23012
  });
22994
23013
  }
22995
- if (!state58.stopFired && percent >= cfg.stopPercent) {
22996
- state58.stopFired = true;
23014
+ if (!state56.stopFired && percent >= cfg.stopPercent) {
23015
+ state56.stopFired = true;
22997
23016
  api.log.warn("token-budget: hard limit reached \u2014 agent loop will be stopped", {
22998
- total: state58.totalTokens,
23017
+ total: state56.totalTokens,
22999
23018
  limit: cfg.limit
23000
23019
  });
23001
23020
  api.emitCustom("token-budget:limit_reached", {
23002
- total: state58.totalTokens,
23021
+ total: state56.totalTokens,
23003
23022
  limit: cfg.limit
23004
23023
  });
23005
23024
  }
23006
23025
  });
23007
- state58.hookUnregister = api.registerHook("Stop", void 0, () => {
23008
- if (cfg.limit <= 0 || !state58.stopFired) return;
23026
+ state56.hookUnregister = api.registerHook("Stop", void 0, () => {
23027
+ if (cfg.limit <= 0 || !state56.stopFired) return;
23009
23028
  return {
23010
23029
  decision: "block",
23011
- reason: `token-budget: session token limit reached (${state58.totalTokens.toLocaleString()} / ${cfg.limit.toLocaleString()} tokens). The budget is exhausted \u2014 wrap up the current task and summarize what was accomplished.`
23030
+ reason: `token-budget: session token limit reached (${state56.totalTokens.toLocaleString()} / ${cfg.limit.toLocaleString()} tokens). The budget is exhausted \u2014 wrap up the current task and summarize what was accomplished.`
23012
23031
  };
23013
23032
  });
23014
- state58.postHookUnregister = api.registerHook("PostToolUse", "*", () => {
23033
+ state56.postHookUnregister = api.registerHook("PostToolUse", "*", () => {
23015
23034
  if (cfg.limit <= 0) return;
23016
- const percent = Math.round(state58.totalTokens / cfg.limit * 100);
23017
- const remaining = Math.max(cfg.limit - state58.totalTokens, 0);
23018
- if (state58.stopFired && !state58.stopContextInjected) {
23019
- state58.stopContextInjected = true;
23035
+ const percent = Math.round(state56.totalTokens / cfg.limit * 100);
23036
+ const remaining = Math.max(cfg.limit - state56.totalTokens, 0);
23037
+ if (state56.stopFired && !state56.stopContextInjected) {
23038
+ state56.stopContextInjected = true;
23020
23039
  return {
23021
23040
  additionalContext: `
23022
- \u{1F6D1} token-budget: HARD LIMIT REACHED \u2014 ${state58.totalTokens.toLocaleString()} / ${cfg.limit.toLocaleString()} tokens (${percent}%). You must stop here. Do NOT start any new task. Summarize what was accomplished and list any remaining work.`
23041
+ \u{1F6D1} token-budget: HARD LIMIT REACHED \u2014 ${state56.totalTokens.toLocaleString()} / ${cfg.limit.toLocaleString()} tokens (${percent}%). You must stop here. Do NOT start any new task. Summarize what was accomplished and list any remaining work.`
23023
23042
  };
23024
23043
  }
23025
- if (state58.warningFired && !state58.warnContextInjected) {
23026
- state58.warnContextInjected = true;
23044
+ if (state56.warningFired && !state56.warnContextInjected) {
23045
+ state56.warnContextInjected = true;
23027
23046
  return {
23028
23047
  additionalContext: `
23029
- \u26A0\uFE0F token-budget: ${percent}% of budget used (${state58.totalTokens.toLocaleString()} / ${cfg.limit.toLocaleString()} tokens, ${remaining.toLocaleString()} remaining). Start wrapping up \u2014 prioritize finishing the current task over starting new ones.`
23048
+ \u26A0\uFE0F token-budget: ${percent}% of budget used (${state56.totalTokens.toLocaleString()} / ${cfg.limit.toLocaleString()} tokens, ${remaining.toLocaleString()} remaining). Start wrapping up \u2014 prioritize finishing the current task over starting new ones.`
23030
23049
  };
23031
23050
  }
23032
23051
  return;
@@ -23039,7 +23058,7 @@ var plugin61 = {
23039
23058
  category: "Meta",
23040
23059
  mutating: false,
23041
23060
  async execute() {
23042
- const consumed = state58.totalTokens;
23061
+ const consumed = state56.totalTokens;
23043
23062
  const limit = cfg.limit;
23044
23063
  const percent = limit > 0 ? Math.round(consumed / limit * 100) : 0;
23045
23064
  const remaining = limit > 0 ? Math.max(limit - consumed, 0) : Infinity;
@@ -23049,7 +23068,7 @@ var plugin61 = {
23049
23068
  consumed,
23050
23069
  remaining,
23051
23070
  percent,
23052
- requestCount: state58.requestCount,
23071
+ requestCount: state56.requestCount,
23053
23072
  // The EFFECTIVE thresholds, after out-of-range values fall back to
23054
23073
  // the defaults and warn/stop are ordered. Without these the user
23055
23074
  // cannot tell that a rejected or clamped setting is not in force.
@@ -23057,12 +23076,12 @@ var plugin61 = {
23057
23076
  stopPercent: cfg.stopPercent,
23058
23077
  model: cfg.model === "" ? null : cfg.model,
23059
23078
  breakdown: {
23060
- prompt: state58.totalPromptTokens,
23061
- completion: state58.totalCompletionTokens
23079
+ prompt: state56.totalPromptTokens,
23080
+ completion: state56.totalCompletionTokens
23062
23081
  },
23063
- warningFired: state58.warningFired,
23064
- stopFired: state58.stopFired,
23065
- lastRequest: state58.lastRequest
23082
+ warningFired: state56.warningFired,
23083
+ stopFired: state56.stopFired,
23084
+ lastRequest: state56.lastRequest
23066
23085
  };
23067
23086
  }
23068
23087
  });
@@ -23076,30 +23095,30 @@ var plugin61 = {
23076
23095
  teardown(api) {
23077
23096
  clearRegistrations2();
23078
23097
  const final = {
23079
- totalTokens: state58.totalTokens,
23080
- requestCount: state58.requestCount,
23081
- warningFired: state58.warningFired,
23082
- stopFired: state58.stopFired
23098
+ totalTokens: state56.totalTokens,
23099
+ requestCount: state56.requestCount,
23100
+ warningFired: state56.warningFired,
23101
+ stopFired: state56.stopFired
23083
23102
  };
23084
- state58.totalTokens = 0;
23085
- state58.totalPromptTokens = 0;
23086
- state58.totalCompletionTokens = 0;
23087
- state58.requestCount = 0;
23088
- state58.warningFired = false;
23089
- state58.stopFired = false;
23090
- state58.warnContextInjected = false;
23091
- state58.stopContextInjected = false;
23092
- state58.lastRequest = null;
23103
+ state56.totalTokens = 0;
23104
+ state56.totalPromptTokens = 0;
23105
+ state56.totalCompletionTokens = 0;
23106
+ state56.requestCount = 0;
23107
+ state56.warningFired = false;
23108
+ state56.stopFired = false;
23109
+ state56.warnContextInjected = false;
23110
+ state56.stopContextInjected = false;
23111
+ state56.lastRequest = null;
23093
23112
  api.log.info("token-budget: teardown complete", { final });
23094
23113
  },
23095
23114
  async health() {
23096
23115
  return {
23097
23116
  ok: true,
23098
- message: state58.lastRequest === null ? `token-budget: ${state58.totalTokens.toLocaleString()} tokens across ${state58.requestCount} request(s)` : `token-budget: ${state58.totalTokens.toLocaleString()} tokens, last ${state58.lastRequest.model} at ${state58.lastRequest.when}`,
23099
- totalTokens: state58.totalTokens,
23100
- requestCount: state58.requestCount,
23101
- warningFired: state58.warningFired,
23102
- stopFired: state58.stopFired
23117
+ message: state56.lastRequest === null ? `token-budget: ${state56.totalTokens.toLocaleString()} tokens across ${state56.requestCount} request(s)` : `token-budget: ${state56.totalTokens.toLocaleString()} tokens, last ${state56.lastRequest.model} at ${state56.lastRequest.when}`,
23118
+ totalTokens: state56.totalTokens,
23119
+ requestCount: state56.requestCount,
23120
+ warningFired: state56.warningFired,
23121
+ stopFired: state56.stopFired
23103
23122
  };
23104
23123
  }
23105
23124
  };
@@ -23145,7 +23164,7 @@ function computeThrottleDelay(entries, now, limit, projected) {
23145
23164
  const oldest = sorted[0];
23146
23165
  return oldest ? Math.max(0, oldest.at + WINDOW_MS - now) : 0;
23147
23166
  }
23148
- var state59 = {
23167
+ var state57 = {
23149
23168
  window: [],
23150
23169
  invocations: 0,
23151
23170
  throttled: 0,
@@ -23218,16 +23237,16 @@ var plugin62 = {
23218
23237
  }
23219
23238
  },
23220
23239
  setup(api) {
23221
- state59.window = [];
23222
- state59.invocations = 0;
23223
- state59.throttled = 0;
23224
- state59.totalDelayMs = 0;
23225
- if (state59.extensionUnregister) {
23240
+ state57.window = [];
23241
+ state57.invocations = 0;
23242
+ state57.throttled = 0;
23243
+ state57.totalDelayMs = 0;
23244
+ if (state57.extensionUnregister) {
23226
23245
  try {
23227
- state59.extensionUnregister();
23246
+ state57.extensionUnregister();
23228
23247
  } catch {
23229
23248
  }
23230
- state59.extensionUnregister = null;
23249
+ state57.extensionUnregister = null;
23231
23250
  }
23232
23251
  const cfg = readConfig54(api.config.extensions?.["token-throttle"]);
23233
23252
  if (cfg.enabled) {
@@ -23236,21 +23255,21 @@ var plugin62 = {
23236
23255
  kind: "throttle",
23237
23256
  wraps: ["request"]
23238
23257
  });
23239
- state59.extensionUnregister = api.extensions.register({
23258
+ state57.extensionUnregister = api.extensions.register({
23240
23259
  name: "token-throttle",
23241
23260
  owner: "token-throttle",
23242
23261
  async wrapProviderRunner(_ctx, request, inner) {
23243
23262
  const signal = _ctx?.signal;
23244
23263
  const req = request ?? {};
23245
- state59.invocations += 1;
23264
+ state57.invocations += 1;
23246
23265
  const now = Date.now();
23247
- state59.window = pruneWindow(state59.window, now);
23266
+ state57.window = pruneWindow(state57.window, now);
23248
23267
  const projected = estimateRequestTokens(req, cfg.charsPerToken);
23249
- const rawDelay = computeThrottleDelay(state59.window, now, cfg.tokensPerMinute, projected);
23268
+ const rawDelay = computeThrottleDelay(state57.window, now, cfg.tokensPerMinute, projected);
23250
23269
  const delay = Math.min(rawDelay, cfg.maxDelayMs);
23251
23270
  if (delay > 0) {
23252
- state59.throttled += 1;
23253
- state59.totalDelayMs += delay;
23271
+ state57.throttled += 1;
23272
+ state57.totalDelayMs += delay;
23254
23273
  api.metrics.counter("throttled");
23255
23274
  api.metrics.histogram("delay_ms", delay);
23256
23275
  api.log.info("token-throttle: delaying provider call", { delayMs: delay, projected });
@@ -23258,7 +23277,7 @@ var plugin62 = {
23258
23277
  }
23259
23278
  const response = await inner(_ctx, request);
23260
23279
  const used = (response?.usage?.input ?? 0) + (response?.usage?.output ?? 0) || projected;
23261
- state59.window.push({ at: Date.now(), tokens: used });
23280
+ state57.window.push({ at: Date.now(), tokens: used });
23262
23281
  return response;
23263
23282
  }
23264
23283
  });
@@ -23272,7 +23291,7 @@ var plugin62 = {
23272
23291
  mutating: false,
23273
23292
  async execute() {
23274
23293
  const now = Date.now();
23275
- const live = pruneWindow(state59.window, now);
23294
+ const live = pruneWindow(state57.window, now);
23276
23295
  return {
23277
23296
  ok: true,
23278
23297
  enabled: cfg.enabled,
@@ -23281,9 +23300,9 @@ var plugin62 = {
23281
23300
  windowSpend: windowSpend(live),
23282
23301
  windowEntries: live.length,
23283
23302
  counters: {
23284
- invocations: state59.invocations,
23285
- throttled: state59.throttled,
23286
- totalDelayMs: state59.totalDelayMs
23303
+ invocations: state57.invocations,
23304
+ throttled: state57.throttled,
23305
+ totalDelayMs: state57.totalDelayMs
23287
23306
  }
23288
23307
  };
23289
23308
  }
@@ -23295,32 +23314,32 @@ var plugin62 = {
23295
23314
  });
23296
23315
  },
23297
23316
  teardown(api) {
23298
- if (state59.extensionUnregister) {
23317
+ if (state57.extensionUnregister) {
23299
23318
  try {
23300
- state59.extensionUnregister();
23319
+ state57.extensionUnregister();
23301
23320
  } catch {
23302
23321
  }
23303
- state59.extensionUnregister = null;
23322
+ state57.extensionUnregister = null;
23304
23323
  }
23305
23324
  const final = {
23306
- invocations: state59.invocations,
23307
- throttled: state59.throttled,
23308
- totalDelayMs: state59.totalDelayMs
23325
+ invocations: state57.invocations,
23326
+ throttled: state57.throttled,
23327
+ totalDelayMs: state57.totalDelayMs
23309
23328
  };
23310
- state59.window = [];
23311
- state59.invocations = 0;
23312
- state59.throttled = 0;
23313
- state59.totalDelayMs = 0;
23329
+ state57.window = [];
23330
+ state57.invocations = 0;
23331
+ state57.throttled = 0;
23332
+ state57.totalDelayMs = 0;
23314
23333
  api.log.info("token-throttle: teardown complete", { final });
23315
23334
  },
23316
23335
  async health() {
23317
23336
  return {
23318
23337
  ok: true,
23319
- message: `token-throttle: ${state59.throttled} throttle(s) of ${state59.invocations} call(s), ${state59.totalDelayMs}ms total delay`,
23338
+ message: `token-throttle: ${state57.throttled} throttle(s) of ${state57.invocations} call(s), ${state57.totalDelayMs}ms total delay`,
23320
23339
  counters: {
23321
- invocations: state59.invocations,
23322
- throttled: state59.throttled,
23323
- totalDelayMs: state59.totalDelayMs
23340
+ invocations: state57.invocations,
23341
+ throttled: state57.throttled,
23342
+ totalDelayMs: state57.totalDelayMs
23324
23343
  }
23325
23344
  };
23326
23345
  }
@@ -23330,7 +23349,7 @@ var token_throttle_default = plugin62;
23330
23349
  // src/type-gate/index.ts
23331
23350
  import { existsSync as existsSync6 } from "node:fs";
23332
23351
  var API_VERSION41 = "^0.1.10";
23333
- var state60 = {
23352
+ var state58 = {
23334
23353
  invocationCount: 0,
23335
23354
  runCount: 0,
23336
23355
  passCount: 0,
@@ -23493,14 +23512,14 @@ var plugin63 = {
23493
23512
  }
23494
23513
  },
23495
23514
  setup(api) {
23496
- state60.invocationCount = 0;
23497
- state60.runCount = 0;
23498
- state60.passCount = 0;
23499
- state60.failCount = 0;
23500
- state60.errorCount = 0;
23501
- state60.skippedCount = 0;
23502
- state60.lastResult = null;
23503
- state60.hookUnregister = releaseHandle(state60.hookUnregister);
23515
+ state58.invocationCount = 0;
23516
+ state58.runCount = 0;
23517
+ state58.passCount = 0;
23518
+ state58.failCount = 0;
23519
+ state58.errorCount = 0;
23520
+ state58.skippedCount = 0;
23521
+ state58.lastResult = null;
23522
+ state58.hookUnregister = releaseHandle(state58.hookUnregister);
23504
23523
  const cfg = readConfig55(api.config.extensions?.["type-gate"]);
23505
23524
  const hook = async (input) => {
23506
23525
  if (!cfg.enabled) return;
@@ -23511,27 +23530,27 @@ var plugin63 = {
23511
23530
  if (!withinProject(sourcePath)) return;
23512
23531
  const ext = sourcePath.includes(".") ? sourcePath.slice(sourcePath.lastIndexOf(".")).toLowerCase() : "";
23513
23532
  if (!runOnChangeSet2.has(ext)) {
23514
- state60.skippedCount += 1;
23533
+ state58.skippedCount += 1;
23515
23534
  return;
23516
23535
  }
23517
- state60.invocationCount += 1;
23536
+ state58.invocationCount += 1;
23518
23537
  const result = await runTypeCheck(cfg);
23519
23538
  if (!result) {
23520
- state60.errorCount += 1;
23539
+ state58.errorCount += 1;
23521
23540
  return;
23522
23541
  }
23523
- state60.runCount += 1;
23524
- state60.lastResult = {
23542
+ state58.runCount += 1;
23543
+ state58.lastResult = {
23525
23544
  passed: result.passed,
23526
23545
  errorCount: result.errorCount,
23527
23546
  durationMs: result.durationMs,
23528
23547
  when: (/* @__PURE__ */ new Date()).toISOString()
23529
23548
  };
23530
23549
  if (result.passed) {
23531
- state60.passCount += 1;
23550
+ state58.passCount += 1;
23532
23551
  return;
23533
23552
  }
23534
- state60.failCount += 1;
23553
+ state58.failCount += 1;
23535
23554
  const errorList = result.errors.map((e) => ` \u274C ${e}`).join("\n");
23536
23555
  const message = `
23537
23556
  \u274C type-gate: Type check failed after editing ${sourcePath} (${result.durationMs}ms).
@@ -23546,7 +23565,7 @@ Fix the type error(s) or adjust the change.`;
23546
23565
  }
23547
23566
  return { additionalContext: message };
23548
23567
  };
23549
- state60.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
23568
+ state58.hookUnregister = api.registerHook("PostToolUse", "write|edit", hook, { background: true });
23550
23569
  api.tools.register({
23551
23570
  name: "type_gate_status",
23552
23571
  description: "Reports type-gate state: command, tsconfig, severity, and per-session pass/fail/error counters.",
@@ -23564,14 +23583,14 @@ Fix the type error(s) or adjust the change.`;
23564
23583
  maxErrors: cfg.maxErrors,
23565
23584
  runOnChange: cfg.runOnChange,
23566
23585
  counters: {
23567
- invocations: state60.invocationCount,
23568
- runs: state60.runCount,
23569
- passed: state60.passCount,
23570
- failed: state60.failCount,
23571
- errors: state60.errorCount,
23572
- skipped: state60.skippedCount
23586
+ invocations: state58.invocationCount,
23587
+ runs: state58.runCount,
23588
+ passed: state58.passCount,
23589
+ failed: state58.failCount,
23590
+ errors: state58.errorCount,
23591
+ skipped: state58.skippedCount
23573
23592
  },
23574
- lastResult: state60.lastResult
23593
+ lastResult: state58.lastResult
23575
23594
  };
23576
23595
  }
23577
23596
  });
@@ -23583,43 +23602,43 @@ Fix the type error(s) or adjust the change.`;
23583
23602
  });
23584
23603
  },
23585
23604
  teardown(api) {
23586
- if (state60.hookUnregister) {
23605
+ if (state58.hookUnregister) {
23587
23606
  try {
23588
- state60.hookUnregister();
23607
+ state58.hookUnregister();
23589
23608
  } catch {
23590
23609
  }
23591
- state60.hookUnregister = null;
23610
+ state58.hookUnregister = null;
23592
23611
  }
23593
23612
  const final = {
23594
- invocations: state60.invocationCount,
23595
- runs: state60.runCount,
23596
- passed: state60.passCount,
23597
- failed: state60.failCount,
23598
- errors: state60.errorCount,
23599
- skipped: state60.skippedCount
23613
+ invocations: state58.invocationCount,
23614
+ runs: state58.runCount,
23615
+ passed: state58.passCount,
23616
+ failed: state58.failCount,
23617
+ errors: state58.errorCount,
23618
+ skipped: state58.skippedCount
23600
23619
  };
23601
- state60.invocationCount = 0;
23602
- state60.runCount = 0;
23603
- state60.passCount = 0;
23604
- state60.failCount = 0;
23605
- state60.errorCount = 0;
23606
- state60.skippedCount = 0;
23607
- state60.lastResult = null;
23620
+ state58.invocationCount = 0;
23621
+ state58.runCount = 0;
23622
+ state58.passCount = 0;
23623
+ state58.failCount = 0;
23624
+ state58.errorCount = 0;
23625
+ state58.skippedCount = 0;
23626
+ state58.lastResult = null;
23608
23627
  api.log.info("type-gate: teardown complete", { final });
23609
23628
  },
23610
23629
  async health() {
23611
23630
  return {
23612
23631
  ok: true,
23613
- message: state60.lastResult ? `type-gate: ${state60.runCount} run(s), last ${state60.lastResult.passed ? "PASSED" : "FAILED"} (${state60.lastResult.errorCount} errors)` : `type-gate: ${state60.invocationCount} invocation(s), ${state60.runCount} run(s)`,
23632
+ message: state58.lastResult ? `type-gate: ${state58.runCount} run(s), last ${state58.lastResult.passed ? "PASSED" : "FAILED"} (${state58.lastResult.errorCount} errors)` : `type-gate: ${state58.invocationCount} invocation(s), ${state58.runCount} run(s)`,
23614
23633
  counters: {
23615
- invocations: state60.invocationCount,
23616
- runs: state60.runCount,
23617
- passed: state60.passCount,
23618
- failed: state60.failCount,
23619
- errors: state60.errorCount,
23620
- skipped: state60.skippedCount
23621
- },
23622
- lastResult: state60.lastResult
23634
+ invocations: state58.invocationCount,
23635
+ runs: state58.runCount,
23636
+ passed: state58.passCount,
23637
+ failed: state58.failCount,
23638
+ errors: state58.errorCount,
23639
+ skipped: state58.skippedCount
23640
+ },
23641
+ lastResult: state58.lastResult
23623
23642
  };
23624
23643
  }
23625
23644
  };