@integrity-labs/agt-cli 0.28.62 → 0.28.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/agt.js CHANGED
@@ -37,7 +37,7 @@ import {
37
37
  success,
38
38
  table,
39
39
  warn
40
- } from "../chunk-QQGXIZVB.js";
40
+ } from "../chunk-5H3EMCNV.js";
41
41
  import {
42
42
  CHANNEL_REGISTRY,
43
43
  DEPLOYMENT_TEMPLATES,
@@ -4777,7 +4777,7 @@ import { execFileSync, execSync } from "child_process";
4777
4777
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4778
4778
  import chalk18 from "chalk";
4779
4779
  import ora16 from "ora";
4780
- var cliVersion = true ? "0.28.62" : "dev";
4780
+ var cliVersion = true ? "0.28.63" : "dev";
4781
4781
  async function fetchLatestVersion() {
4782
4782
  const host2 = getHost();
4783
4783
  if (!host2) return null;
@@ -5791,7 +5791,7 @@ function handleError(err) {
5791
5791
  }
5792
5792
 
5793
5793
  // src/bin/agt.ts
5794
- var cliVersion2 = true ? "0.28.62" : "dev";
5794
+ var cliVersion2 = true ? "0.28.63" : "dev";
5795
5795
  var program = new Command();
5796
5796
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
5797
5797
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -7347,7 +7347,7 @@ function requireHost() {
7347
7347
  }
7348
7348
 
7349
7349
  // src/lib/api-client.ts
7350
- var agtCliVersion = true ? "0.28.62" : "dev";
7350
+ var agtCliVersion = true ? "0.28.63" : "dev";
7351
7351
  var lastConfigHash = null;
7352
7352
  function setConfigHash(hash) {
7353
7353
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8643,4 +8643,4 @@ export {
8643
8643
  managerInstallSystemUnitCommand,
8644
8644
  managerUninstallSystemUnitCommand
8645
8645
  };
8646
- //# sourceMappingURL=chunk-QQGXIZVB.js.map
8646
+ //# sourceMappingURL=chunk-5H3EMCNV.js.map
@@ -27,7 +27,7 @@ import {
27
27
  requireHost,
28
28
  safeWriteJsonAtomic,
29
29
  setConfigHash
30
- } from "../chunk-QQGXIZVB.js";
30
+ } from "../chunk-5H3EMCNV.js";
31
31
  import {
32
32
  getProjectDir as getProjectDir2,
33
33
  getReadyTasks,
@@ -1060,6 +1060,8 @@ function formatStatusMessage(events, windowMs) {
1060
1060
  var DEFAULT_WINDOW_MS2 = 6e5;
1061
1061
  var DEFAULT_MIN_TRANSITIONS = 4;
1062
1062
  var DEFAULT_MIN_DISTINCT = 2;
1063
+ var DEFAULT_LONG_WINDOW_MS = 36e5;
1064
+ var DEFAULT_LONG_MIN_TRANSITIONS = 4;
1063
1065
  function readEnvNumber2(name, fallback) {
1064
1066
  const raw = process.env[name];
1065
1067
  if (!raw) return fallback;
@@ -1073,6 +1075,8 @@ var McpFlapDampener = class {
1073
1075
  windowMs;
1074
1076
  minTransitions;
1075
1077
  minDistinct;
1078
+ longWindowMs;
1079
+ longMinTransitions;
1076
1080
  now;
1077
1081
  history = /* @__PURE__ */ new Map();
1078
1082
  flapping = /* @__PURE__ */ new Set();
@@ -1080,6 +1084,8 @@ var McpFlapDampener = class {
1080
1084
  this.windowMs = opts.windowMs ?? readEnvNumber2("AGT_MCP_FLAP_WINDOW_MS", DEFAULT_WINDOW_MS2);
1081
1085
  this.minTransitions = opts.minTransitions ?? readEnvNumber2("AGT_MCP_FLAP_MIN_TRANSITIONS", DEFAULT_MIN_TRANSITIONS);
1082
1086
  this.minDistinct = opts.minDistinct ?? readEnvNumber2("AGT_MCP_FLAP_MIN_DISTINCT", DEFAULT_MIN_DISTINCT);
1087
+ this.longWindowMs = opts.longWindowMs ?? readEnvNumber2("AGT_MCP_FLAP_LONG_WINDOW_MS", DEFAULT_LONG_WINDOW_MS);
1088
+ this.longMinTransitions = opts.longMinTransitions ?? readEnvNumber2("AGT_MCP_FLAP_LONG_MIN_TRANSITIONS", DEFAULT_LONG_MIN_TRANSITIONS);
1083
1089
  this.now = opts.now ?? Date.now;
1084
1090
  if (!Number.isFinite(this.windowMs) || this.windowMs < 1e3) {
1085
1091
  throw new Error("mcp-flap-dampener windowMs must be a finite number >= 1000");
@@ -1090,6 +1096,12 @@ var McpFlapDampener = class {
1090
1096
  if (!Number.isFinite(this.minDistinct) || this.minDistinct < 2) {
1091
1097
  throw new Error("mcp-flap-dampener minDistinct must be a finite number >= 2");
1092
1098
  }
1099
+ if (!Number.isFinite(this.longWindowMs) || this.longWindowMs < this.windowMs) {
1100
+ throw new Error("mcp-flap-dampener longWindowMs must be a finite number >= windowMs");
1101
+ }
1102
+ if (!Number.isFinite(this.longMinTransitions) || this.longMinTransitions < 2) {
1103
+ throw new Error("mcp-flap-dampener longMinTransitions must be a finite number >= 2");
1104
+ }
1093
1105
  }
1094
1106
  key(codeName, channel) {
1095
1107
  return `${codeName}\0${channel}`;
@@ -1103,34 +1115,58 @@ var McpFlapDampener = class {
1103
1115
  record(codeName, channel, signature) {
1104
1116
  const k = this.key(codeName, channel);
1105
1117
  const at = this.now();
1106
- const cutoff = at - this.windowMs;
1118
+ const cutoff = at - this.longWindowMs;
1107
1119
  const prior = (this.history.get(k) ?? []).filter((o) => o.at >= cutoff);
1108
1120
  prior.push({ sig: signature, at });
1109
1121
  this.history.set(k, prior);
1110
- let transitions = 0;
1111
- for (let i = 1; i < prior.length; i++) {
1112
- if (prior[i].sig !== prior[i - 1].sig) transitions++;
1113
- }
1114
- const distinctStates = new Set(prior.map((o) => o.sig)).size;
1115
- const revisited = prior.slice(0, -1).some((o, i) => o.sig === signature && i !== prior.length - 2);
1122
+ const fast = this.windowMetrics(prior, at - this.windowMs);
1123
+ const slow = this.windowMetrics(prior, at - this.longWindowMs);
1124
+ const fastOsc = fast.transitions >= this.minTransitions && fast.distinctStates >= this.minDistinct && fast.revisited;
1125
+ const slowOsc = slow.transitions >= this.longMinTransitions && slow.distinctStates >= this.minDistinct && slow.revisited;
1126
+ const oscillating = fastOsc || slowOsc;
1127
+ const tier = fastOsc ? "fast" : slowOsc ? "slow" : null;
1116
1128
  const transitionNow = prior.length >= 2 && prior[prior.length - 1].sig !== prior[prior.length - 2].sig;
1117
- const oscillating = transitions >= this.minTransitions && distinctStates >= this.minDistinct && revisited;
1118
1129
  const wasFlapping = this.flapping.has(k);
1119
1130
  let onset = false;
1120
1131
  if (wasFlapping) {
1121
- if (!transitionNow) this.flapping.delete(k);
1132
+ if (!transitionNow) {
1133
+ this.flapping.delete(k);
1134
+ this.history.set(k, [{ sig: signature, at }]);
1135
+ }
1122
1136
  } else if (transitionNow && oscillating) {
1123
1137
  this.flapping.add(k);
1124
1138
  onset = true;
1125
1139
  }
1140
+ const reported = tier === "slow" ? slow : fast;
1126
1141
  return {
1127
1142
  flapping: this.flapping.has(k),
1128
- distinctStates,
1129
- transitions,
1143
+ distinctStates: reported.distinctStates,
1144
+ transitions: reported.transitions,
1130
1145
  windowCount: prior.length,
1131
- onset
1146
+ onset,
1147
+ tier,
1148
+ longTransitions: slow.transitions,
1149
+ longDistinctStates: slow.distinctStates
1132
1150
  };
1133
1151
  }
1152
+ /**
1153
+ * Transitions / distinct signatures / revisit flag for the observations that
1154
+ * fall inside `[windowStart, now]`. The latest observation (the one just
1155
+ * recorded) is always in-window. A revisit = the latest signature appears
1156
+ * earlier in the sub-window but NOT as the immediately-preceding observation,
1157
+ * so strictly-monotonic growth (A→B→C→D) never counts as a revisit.
1158
+ */
1159
+ windowMetrics(prior, windowStart) {
1160
+ const inWin = prior.filter((o) => o.at >= windowStart);
1161
+ let transitions = 0;
1162
+ for (let i = 1; i < inWin.length; i++) {
1163
+ if (inWin[i].sig !== inWin[i - 1].sig) transitions++;
1164
+ }
1165
+ const distinctStates = new Set(inWin.map((o) => o.sig)).size;
1166
+ const latest = inWin[inWin.length - 1];
1167
+ const revisited = latest ? inWin.slice(0, -1).some((o, i) => o.sig === latest.sig && i !== inWin.length - 2) : false;
1168
+ return { transitions, distinctStates, revisited };
1169
+ }
1134
1170
  /** True if (codeName, channel) is currently dampened. */
1135
1171
  isFlapping(codeName, channel) {
1136
1172
  return this.flapping.has(this.key(codeName, channel));
@@ -6582,7 +6618,7 @@ function checkMcpConfigDriftAndScheduleRestart(codeName, projectDir) {
6582
6618
  );
6583
6619
  } else if (flapSuppressed) {
6584
6620
  log(
6585
- `[mcp-flap-dampener] .mcp.json membership drift for '${codeName}' [${decision.addedOrRemoved.join(", ")}] held \u2014 managed-MCP set is flapping, adopting baseline WITHOUT restart until it settles (ENG-6123)`
6621
+ `[mcp-flap-dampener] .mcp.json membership drift for '${codeName}' [${decision.addedOrRemoved.join(", ")}] held \u2014 managed-MCP set is flapping, adopting baseline WITHOUT restart until it settles (ENG-6123, ENG-6512)`
6586
6622
  );
6587
6623
  } else if (decision.restart) {
6588
6624
  clearPresenceReaperStateForKeys(codeName, new Set(decision.addedOrRemoved));
@@ -6698,7 +6734,7 @@ var cachedMaintenanceWindow = null;
6698
6734
  var lastVersionCheckAt = 0;
6699
6735
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6700
6736
  var lastResponsivenessProbeAt = 0;
6701
- var agtCliVersion = true ? "0.28.62" : "dev";
6737
+ var agtCliVersion = true ? "0.28.63" : "dev";
6702
6738
  function resolveBrewPath(execFileSync4) {
6703
6739
  try {
6704
6740
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -9314,7 +9350,7 @@ async function processAgent(agent, agentStates) {
9314
9350
  const intFlap = mcpFlapDampener.record(agent.code_name, FLAP_CHANNEL_INTEGRATIONS, intMembership);
9315
9351
  if (intFlap.onset) {
9316
9352
  log(
9317
- `[mcp-flap-dampener] integration set for '${agent.code_name}' is FLAPPING (${intFlap.transitions} transitions / ${intFlap.distinctStates} states in window) \u2014 suppressing integration-update notices until it settles (ENG-6123)`
9353
+ `[mcp-flap-dampener] integration set for '${agent.code_name}' is FLAPPING (${intFlap.tier} tier: ${intFlap.transitions} transitions / ${intFlap.distinctStates} states in window) \u2014 suppressing integration-update notices until it settles (ENG-6123, ENG-6512)`
9318
9354
  );
9319
9355
  recordConfigChurnEvent(agent.agent_id, agent.code_name, FLAP_CHANNEL_INTEGRATIONS, intMembership);
9320
9356
  }
@@ -9403,7 +9439,7 @@ async function processAgent(agent, agentStates) {
9403
9439
  const mcpFlap = mcpFlapDampener.record(agent.code_name, FLAP_CHANNEL_MANAGED_MCP, mcpMembership);
9404
9440
  if (mcpFlap.onset) {
9405
9441
  log(
9406
- `[mcp-flap-dampener] managed-MCP set for '${agent.code_name}' is FLAPPING (${mcpFlap.transitions} transitions / ${mcpFlap.distinctStates} states in window) \u2014 suppressing mcp-update notice + restart until it settles (ENG-6123)`
9442
+ `[mcp-flap-dampener] managed-MCP set for '${agent.code_name}' is FLAPPING (${mcpFlap.tier} tier: ${mcpFlap.transitions} transitions / ${mcpFlap.distinctStates} states in window) \u2014 suppressing mcp-update notice + restart until it settles (ENG-6123, ENG-6512)`
9407
9443
  );
9408
9444
  recordConfigChurnEvent(agent.agent_id, agent.code_name, FLAP_CHANNEL_MANAGED_MCP, mcpMembership);
9409
9445
  }