@integrity-labs/agt-cli 0.28.352 → 0.28.354

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.
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-WMQO3QKU.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-SZ5VHS4C.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-KO2HWC7E.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-LLUV4KX6.js.map
@@ -30,6 +30,7 @@ import {
30
30
  getHostId,
31
31
  givenUpMcpServerKeys,
32
32
  liveProxyExtraHeaderVars,
33
+ parseOpencodeModelRef,
33
34
  pinAllowsUrgent,
34
35
  provision,
35
36
  provisionAutoKanbanProgressHook,
@@ -47,7 +48,7 @@ import {
47
48
  safeWriteJsonAtomic,
48
49
  setConfigHash,
49
50
  toOpencodeModel
50
- } from "../chunk-BERN3B42.js";
51
+ } from "../chunk-4ITNBU3K.js";
51
52
  import {
52
53
  getProjectDir as getProjectDir2,
53
54
  getReadyTasks,
@@ -138,16 +139,16 @@ import {
138
139
  takeZombieDetection,
139
140
  transcriptActivityAgeSeconds,
140
141
  writeEgressAllowlist
141
- } from "../chunk-ZALWFOHO.js";
142
+ } from "../chunk-LDIKBFDR.js";
142
143
  import {
143
144
  reapOrphanChannelMcps
144
145
  } from "../chunk-XWVM4KPK.js";
145
146
 
146
147
  // src/lib/manager-worker.ts
147
148
  import { createHash as createHash14 } from "crypto";
148
- import { readFileSync as readFileSync19, writeFileSync as writeFileSync11, mkdirSync as mkdirSync10, existsSync as existsSync13, rmSync as rmSync5, readdirSync as readdirSync5, statSync as statSync4, copyFileSync } from "fs";
149
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync12, mkdirSync as mkdirSync10, existsSync as existsSync13, rmSync as rmSync5, readdirSync as readdirSync5, statSync as statSync4, copyFileSync } from "fs";
149
150
  import { execFileSync as syncExecFile } from "child_process";
150
- import { join as join23, dirname as dirname6, delimiter as pathDelimiter } from "path";
151
+ import { join as join23, dirname as dirname7, delimiter as pathDelimiter } from "path";
151
152
  import { homedir as homedir12 } from "os";
152
153
  import { fileURLToPath } from "url";
153
154
 
@@ -807,6 +808,19 @@ function countByClass(events) {
807
808
  }
808
809
  return { crash, provisioning, "credential-rotation": credentialRotation };
809
810
  }
811
+ function maxProvisioningBucket(events) {
812
+ const buckets = /* @__PURE__ */ new Map();
813
+ for (const e of events) {
814
+ if (!isProvisioningReloadReason(e.reason)) continue;
815
+ const key = e.integrationKey ?? "";
816
+ buckets.set(key, (buckets.get(key) ?? 0) + 1);
817
+ }
818
+ let best = { count: 0, key: "" };
819
+ for (const [key, count] of buckets) {
820
+ if (count > best.count) best = { count, key };
821
+ }
822
+ return best;
823
+ }
810
824
  var DEFAULT_MAX = 2;
811
825
  var DEFAULT_WINDOW_MS = 6e5;
812
826
  var DEFAULT_PROVISIONING_MAX = 5;
@@ -863,20 +877,25 @@ var RestartBreaker = class {
863
877
  * without double-counting events. Callers may still record the reason
864
878
  * via the decision-log for forensics.
865
879
  */
866
- record(codeName, reason) {
880
+ record(codeName, reason, integrationKey) {
867
881
  const existing = this.trips.get(codeName);
868
882
  if (existing) {
883
+ const bucket = maxProvisioningBucket(existing.eventsAtTrip);
869
884
  return {
870
885
  tripped: false,
871
886
  trip: existing,
872
887
  windowCount: existing.eventsAtTrip.length,
873
- classCounts: countByClass(existing.eventsAtTrip)
888
+ classCounts: countByClass(existing.eventsAtTrip),
889
+ maxProvisioningBucket: bucket.count,
890
+ maxProvisioningBucketKey: bucket.key
874
891
  };
875
892
  }
876
893
  const at = this.now();
877
894
  const retentionCutoff = at - this.retentionMs;
878
895
  const prior = (this.events.get(codeName) ?? []).filter((e) => e.at >= retentionCutoff);
879
- prior.push({ reason, at });
896
+ prior.push(
897
+ isProvisioningReloadReason(reason) && integrationKey ? { reason, at, integrationKey } : { reason, at }
898
+ );
880
899
  this.events.set(codeName, prior);
881
900
  const crashCount = prior.filter(
882
901
  (e) => e.at >= at - this.windowMs && restartReasonClass(e.reason) === "crash"
@@ -893,6 +912,7 @@ var RestartBreaker = class {
893
912
  provisioning: provEvents.length,
894
913
  "credential-rotation": credRotCount
895
914
  };
915
+ const provBucket = maxProvisioningBucket(provEvents);
896
916
  let trippedClass;
897
917
  let tripEvents;
898
918
  let tripWindowMs = this.windowMs;
@@ -902,22 +922,36 @@ var RestartBreaker = class {
902
922
  (e) => e.at >= at - this.windowMs && restartReasonClass(e.reason) === "crash"
903
923
  );
904
924
  tripWindowMs = this.windowMs;
905
- } else if (provEvents.length > this.provisioningMax) {
925
+ } else if (provBucket.count > this.provisioningMax) {
906
926
  trippedClass = "provisioning";
907
- tripEvents = provEvents;
927
+ tripEvents = provEvents.filter((e) => (e.integrationKey ?? "") === provBucket.key);
908
928
  tripWindowMs = this.provisioningWindowMs;
909
929
  }
910
930
  if (trippedClass && tripEvents) {
911
931
  const trip = {
912
932
  trippedAt: at,
913
933
  eventsAtTrip: [...tripEvents],
914
- statusMessage: formatStatusMessage(tripEvents, tripWindowMs, trippedClass)
934
+ statusMessage: formatStatusMessage(tripEvents, tripWindowMs, trippedClass, provBucket.key)
915
935
  };
916
936
  this.trips.set(codeName, trip);
917
937
  this.events.delete(codeName);
918
- return { tripped: true, trip, windowCount, classCounts, trippedClass };
938
+ return {
939
+ tripped: true,
940
+ trip,
941
+ windowCount,
942
+ classCounts,
943
+ trippedClass,
944
+ maxProvisioningBucket: provBucket.count,
945
+ maxProvisioningBucketKey: provBucket.key
946
+ };
919
947
  }
920
- return { tripped: false, windowCount, classCounts };
948
+ return {
949
+ tripped: false,
950
+ windowCount,
951
+ classCounts,
952
+ maxProvisioningBucket: provBucket.count,
953
+ maxProvisioningBucketKey: provBucket.key
954
+ };
921
955
  }
922
956
  /** Operator-initiated reset: drops the trip + the events log for this agent. */
923
957
  clear(codeName) {
@@ -948,14 +982,15 @@ var RestartBreaker = class {
948
982
  return (this.events.get(codeName) ?? []).filter((e) => e.at >= cutoff).length;
949
983
  }
950
984
  };
951
- function formatStatusMessage(events, windowMs, klass = "crash") {
985
+ function formatStatusMessage(events, windowMs, klass = "crash", integrationKey = "") {
952
986
  const last = events[events.length - 1];
953
987
  const windowLabel = windowMs < 6e4 ? `${Math.round(windowMs / 1e3)}s` : `${(windowMs / 6e4).toFixed(1).replace(/\.0$/, "")}min`;
954
988
  const reasonCounts = /* @__PURE__ */ new Map();
955
989
  for (const e of events) reasonCounts.set(e.reason, (reasonCounts.get(e.reason) ?? 0) + 1);
956
990
  const breakdown = Array.from(reasonCounts.entries()).map(([r, n]) => `${r}=${n}`).join(", ");
957
991
  const classLabel = klass === "provisioning" ? "provisioning-reload " : "";
958
- return `Circuit breaker tripped: ${events.length} ${classLabel}restarts in ${windowLabel} (${breakdown}); most recent=${last.reason} at ${new Date(last.at).toISOString()}`;
992
+ const integrationLabel = klass === "provisioning" && integrationKey ? ` for integration '${integrationKey}'` : "";
993
+ return `Circuit breaker tripped: ${events.length} ${classLabel}restarts in ${windowLabel}${integrationLabel} (${breakdown}); most recent=${last.reason} at ${new Date(last.at).toISOString()}`;
959
994
  }
960
995
 
961
996
  // src/lib/mcp-flap-dampener.ts
@@ -3769,6 +3804,17 @@ var agentState = {
3769
3804
  knownModels: /* @__PURE__ */ new Map(),
3770
3805
  knownTasksHashes: /* @__PURE__ */ new Map(),
3771
3806
  knownIntegrationHashes: /* @__PURE__ */ new Map(),
3807
+ /**
3808
+ * ENG-7812: the integration MEMBERSHIP (sorted `definition_id`s, credential/
3809
+ * config churn ignored) observed on the previous refresh. Diffed against the
3810
+ * current membership each poll to derive which integration(s) an
3811
+ * `integration-change` / `hot-reload-mcp` restart is attributable to, which the
3812
+ * restart breaker buckets its provisioning trip by (so onboarding many distinct
3813
+ * integrations doesn't auto-pause a healthy new agent). In-memory only: a
3814
+ * manager restart re-seeds it on the first poll (that first delta is treated as
3815
+ * "no attribution", which is safe: it only widens, never narrows, the trip).
3816
+ */
3817
+ knownIntegrationMembership: /* @__PURE__ */ new Map(),
3772
3818
  knownManagedMcpHashes: /* @__PURE__ */ new Map(),
3773
3819
  knownManagedMcpStructure: /* @__PURE__ */ new Map(),
3774
3820
  /**
@@ -3804,6 +3850,16 @@ var agentState = {
3804
3850
  // ---------------------------------------------------------------------------
3805
3851
  agentDisplayNames: /* @__PURE__ */ new Map(),
3806
3852
  codeNameToAgentId: /* @__PURE__ */ new Map(),
3853
+ /**
3854
+ * ENG-7812: the most recent integration-membership delta for this agent, used
3855
+ * to attribute a provisioning-reload restart to the integration that caused it.
3856
+ * Set when a poll observes an integration add/remove (the changed
3857
+ * `definition_id`s, `+`-joined); read by `recordRestartForBreaker` when a
3858
+ * provisioning restart fires shortly after. `at` bounds its freshness to the
3859
+ * breaker's provisioning window so a stale delta can't mis-attribute a much
3860
+ * later reprovision (those fall through to the shared unattributed bucket).
3861
+ */
3862
+ provisioningAttribution: /* @__PURE__ */ new Map(),
3807
3863
  /**
3808
3864
  * Set of code_names with a live persistent session managed by this worker.
3809
3865
  * Borderline ownership: written from pollCycle and the persistent-session
@@ -3841,6 +3897,7 @@ function clearAgentState(agentId, codeName) {
3841
3897
  agentState.knownModels.delete(agentId);
3842
3898
  agentState.knownTasksHashes.delete(agentId);
3843
3899
  agentState.knownIntegrationHashes.delete(agentId);
3900
+ agentState.knownIntegrationMembership.delete(agentId);
3844
3901
  agentState.knownManagedMcpHashes.delete(agentId);
3845
3902
  agentState.knownManagedMcpStructure.delete(agentId);
3846
3903
  agentState.knownSenderPolicyHashes.delete(agentId);
@@ -3849,6 +3906,7 @@ function clearAgentState(agentId, codeName) {
3849
3906
  agentState.knownGlobalSkillIds.delete(agentId);
3850
3907
  agentState.agentDisplayNames.delete(codeName);
3851
3908
  agentState.codeNameToAgentId.delete(codeName);
3909
+ agentState.provisioningAttribution.delete(codeName);
3852
3910
  let channelCacheMutated = false;
3853
3911
  for (const key of agentState.knownChannelConfigHashes.keys()) {
3854
3912
  if (key.startsWith(`${agentId}:`)) {
@@ -5579,9 +5637,9 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
5579
5637
  import { spawn, execSync } from "child_process";
5580
5638
  import { createServer } from "net";
5581
5639
  import { randomBytes } from "crypto";
5582
- import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync16 } from "fs";
5640
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "fs";
5583
5641
  import { homedir as homedir10, userInfo } from "os";
5584
- import { join as join20 } from "path";
5642
+ import { join as join20, dirname as dirname6 } from "path";
5585
5643
  var OPENCODE_BIN = process.env["AGT_OPENCODE_BIN"]?.trim() || "opencode";
5586
5644
  var sessions = /* @__PURE__ */ new Map();
5587
5645
  var bridges = /* @__PURE__ */ new Map();
@@ -5592,14 +5650,43 @@ function opencodePaneLogPath(codeName) {
5592
5650
  return join20(homedir10(), ".augmented", codeName, "opencode-serve.log");
5593
5651
  }
5594
5652
  function readProvisionedOpencodeModel(agentDir) {
5653
+ return readOpencodeModelString(join20(agentDir, "provision", "opencode.json"));
5654
+ }
5655
+ function readOpencodeModelString(configPath) {
5595
5656
  try {
5596
- const raw = readFileSync16(join20(agentDir, "provision", "opencode.json"), "utf-8");
5597
- const parsed = JSON.parse(raw);
5657
+ const parsed = JSON.parse(readFileSync16(configPath, "utf-8"));
5598
5658
  return typeof parsed.model === "string" ? parsed.model : null;
5599
5659
  } catch {
5600
5660
  return null;
5601
5661
  }
5602
5662
  }
5663
+ function readOpencodeModelFromConfigDir(configDir) {
5664
+ return parseOpencodeModelRef(readOpencodeModelString(join20(configDir, "opencode.json")));
5665
+ }
5666
+ function materializeEnvPlaceholders(raw, env) {
5667
+ return raw.replace(/\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g, (whole, name) => {
5668
+ const v = env[name];
5669
+ return typeof v === "string" && v.length > 0 ? v : whole;
5670
+ });
5671
+ }
5672
+ function deliverOpencodeConfigToXdg(codeName, projectDir, serveEnv, log2) {
5673
+ let raw;
5674
+ try {
5675
+ raw = readFileSync16(join20(projectDir, "opencode.json"), "utf-8");
5676
+ } catch {
5677
+ return null;
5678
+ }
5679
+ const materialized = materializeEnvPlaceholders(raw, serveEnv);
5680
+ const xdgConfigHome = join20(dirname6(projectDir), "opencode-xdg");
5681
+ try {
5682
+ mkdirSync7(join20(xdgConfigHome, "opencode"), { recursive: true });
5683
+ writeFileSync9(join20(xdgConfigHome, "opencode", "opencode.json"), materialized, { mode: 384 });
5684
+ return xdgConfigHome;
5685
+ } catch (err) {
5686
+ log2(`[opencode-session] failed to deliver opencode config to XDG for '${codeName}': ${err.message}`);
5687
+ return null;
5688
+ }
5689
+ }
5603
5690
  function baseUrlFor(port) {
5604
5691
  return `http://127.0.0.1:${port}`;
5605
5692
  }
@@ -5638,7 +5725,8 @@ async function startOpencodeSession(config2) {
5638
5725
  status: "crashed",
5639
5726
  port: null,
5640
5727
  password: null,
5641
- lastFailureTail: "opencode isolation not implemented (ADR-0047)"
5728
+ lastFailureTail: "opencode isolation not implemented (ADR-0047)",
5729
+ model: null
5642
5730
  };
5643
5731
  sessions.set(codeName, blocked);
5644
5732
  return blocked;
@@ -5650,7 +5738,11 @@ async function startOpencodeSession(config2) {
5650
5738
  status: "starting",
5651
5739
  port: null,
5652
5740
  password: null,
5653
- lastFailureTail: existing?.lastFailureTail ?? null
5741
+ lastFailureTail: existing?.lastFailureTail ?? null,
5742
+ // ENG-7931: parse the resolved model from the provisioned opencode.json
5743
+ // (config.projectDir IS the provision dir the serve reads) so the bridge can
5744
+ // pass it explicitly on session-create + prompt.
5745
+ model: readOpencodeModelFromConfigDir(config2.projectDir)
5654
5746
  };
5655
5747
  sessions.set(codeName, session);
5656
5748
  try {
@@ -5686,6 +5778,8 @@ async function spawnServe(config2, session) {
5686
5778
  };
5687
5779
  if (config2.runId) serveEnv["AGT_RUN_ID"] = config2.runId;
5688
5780
  if (config2.agentTimezone) serveEnv["TZ"] = config2.agentTimezone;
5781
+ const xdgConfigHome = deliverOpencodeConfigToXdg(codeName, projectDir, serveEnv, log2);
5782
+ if (xdgConfigHome) serveEnv["XDG_CONFIG_HOME"] = xdgConfigHome;
5689
5783
  const serveCmd = `${OPENCODE_BIN} serve --hostname 127.0.0.1 --port ${port} --print-logs`;
5690
5784
  log2(`[opencode-session] starting '${tmuxSession}' for '${codeName}' on 127.0.0.1:${port}`);
5691
5785
  const child = spawn(
@@ -5756,7 +5850,11 @@ function getBridge(codeName, port, password) {
5756
5850
  const cached = bridges.get(codeName);
5757
5851
  if (cached && cached.port === port && cached.password === password) return cached.bridge;
5758
5852
  const client2 = new HttpOpencodeClient({ baseUrl: baseUrlFor(port), password });
5759
- const bridge = new OpencodeInboundBridge({ client: client2 });
5853
+ const model = sessions.get(codeName)?.model ?? null;
5854
+ const bridge = new OpencodeInboundBridge({
5855
+ client: client2,
5856
+ sessionDefaults: model ? { model } : void 0
5857
+ });
5760
5858
  bridges.set(codeName, { port, password, bridge });
5761
5859
  return bridge;
5762
5860
  }
@@ -6915,7 +7013,7 @@ async function fireOpencodeScheduledTask(agent, task) {
6915
7013
 
6916
7014
  // src/lib/opencode-telegram-ingest.ts
6917
7015
  import { createHash as createHash13 } from "crypto";
6918
- import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync17, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
7016
+ import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync17, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync10 } from "fs";
6919
7017
  import { randomUUID } from "crypto";
6920
7018
  import { join as join21 } from "path";
6921
7019
 
@@ -7493,7 +7591,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
7493
7591
  const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
7494
7592
  try {
7495
7593
  mkdirSync8(dir, { recursive: true, mode: 448 });
7496
- writeFileSync9(
7594
+ writeFileSync10(
7497
7595
  tmpPath,
7498
7596
  JSON.stringify({
7499
7597
  offset,
@@ -7724,7 +7822,7 @@ function partitionActionableByPoison(actionable, states, config2) {
7724
7822
  }
7725
7823
 
7726
7824
  // src/lib/restart-flags.ts
7727
- import { existsSync as existsSync12, mkdirSync as mkdirSync9, readdirSync as readdirSync4, readFileSync as readFileSync18, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "fs";
7825
+ import { existsSync as existsSync12, mkdirSync as mkdirSync9, readdirSync as readdirSync4, readFileSync as readFileSync18, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync11 } from "fs";
7728
7826
  import { homedir as homedir11 } from "os";
7729
7827
  import { join as join22 } from "path";
7730
7828
  import { randomUUID as randomUUID2 } from "crypto";
@@ -8472,6 +8570,10 @@ var pendingRestartVerifications = /* @__PURE__ */ new Map();
8472
8570
  var restartBreaker = new RestartBreaker();
8473
8571
  var reportedTrips = /* @__PURE__ */ new Map();
8474
8572
  var RESTART_BREAKER_PROVISIONING_MAX = readEnvNumber("AGT_RESTART_BREAKER_PROVISIONING_MAX", 5);
8573
+ var RESTART_BREAKER_PROVISIONING_WINDOW_MS = readEnvNumber(
8574
+ "AGT_RESTART_BREAKER_PROVISIONING_WINDOW_MS",
8575
+ 18e5
8576
+ );
8475
8577
  var mcpFlapDampener = new McpFlapDampener();
8476
8578
  var FLAP_BREAKER_COOLDOWN_MS = readEnvNumber2(
8477
8579
  "AGT_MCP_FLAP_BREAKER_COOLDOWN_MS",
@@ -8510,11 +8612,19 @@ function recordRestartForBreaker(codeName, reason) {
8510
8612
  );
8511
8613
  return;
8512
8614
  }
8513
- const result = restartBreaker.record(codeName, reason);
8615
+ let integrationKey;
8616
+ if (isProvisioningReloadReason(reason)) {
8617
+ const attribution = agentState.provisioningAttribution.get(codeName);
8618
+ if (attribution && Date.now() - attribution.at <= RESTART_BREAKER_PROVISIONING_WINDOW_MS) {
8619
+ integrationKey = attribution.key;
8620
+ }
8621
+ }
8622
+ const result = restartBreaker.record(codeName, reason, integrationKey);
8514
8623
  if (!result.tripped || !result.trip) {
8515
- if (isProvisioningReloadReason(reason) && result.classCounts.provisioning >= RESTART_BREAKER_PROVISIONING_MAX) {
8624
+ if (isProvisioningReloadReason(reason) && result.maxProvisioningBucket >= RESTART_BREAKER_PROVISIONING_MAX) {
8625
+ const culprit = result.maxProvisioningBucketKey ? ` [${result.maxProvisioningBucketKey}]` : "";
8516
8626
  log(
8517
- `[restart-breaker] agent=${codeName} provisioning-reload churn at the trip bar: ${result.classCounts.provisioning} provisioning restarts in window (reason=${reason}); one more will auto-pause the agent \u2014 a freshly-added integration is likely churning (ENG-7560)`
8627
+ `[restart-breaker] agent=${codeName} provisioning-reload churn at the trip bar: ${result.maxProvisioningBucket} restarts for one integration${culprit} in window (reason=${reason}); one more will auto-pause the agent; that integration is likely churning (ENG-7560, ENG-7812)`
8518
8628
  );
8519
8629
  }
8520
8630
  return;
@@ -9342,7 +9452,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
9342
9452
  var lastVersionCheckAt = 0;
9343
9453
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
9344
9454
  var lastResponsivenessProbeAt = 0;
9345
- var agtCliVersion = true ? "0.28.352" : "dev";
9455
+ var agtCliVersion = true ? "0.28.354" : "dev";
9346
9456
  function resolveBrewPath(execFileSync2) {
9347
9457
  try {
9348
9458
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -9437,7 +9547,7 @@ async function ensureToolkitCli(toolkitSlug) {
9437
9547
  toolkitCliEnsured.add(toolkitSlug);
9438
9548
  return;
9439
9549
  }
9440
- brewBinDir = dirname6(brewPath);
9550
+ brewBinDir = dirname7(brewPath);
9441
9551
  const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
9442
9552
  log(`[toolkit-install] ${toolkitSlug}: installing via brew (${pkg})\u2026`);
9443
9553
  if (isRoot) {
@@ -9537,8 +9647,8 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
9537
9647
  }
9538
9648
  if (settings.channelsEnabled === true) return "ok";
9539
9649
  settings.channelsEnabled = true;
9540
- mkdirSync10(dirname6(path), { recursive: true });
9541
- writeFileSync11(path, `${JSON.stringify(settings, null, 2)}
9650
+ mkdirSync10(dirname7(path), { recursive: true });
9651
+ writeFileSync12(path, `${JSON.stringify(settings, null, 2)}
9542
9652
  `);
9543
9653
  log(`[managed-settings] set channelsEnabled:true in ${path} (ENG-5786 \u2014 unblocks Claude Code channels)`);
9544
9654
  return "ok";
@@ -9633,7 +9743,7 @@ async function ensureFrameworkBinary(frameworkId) {
9633
9743
  log(`Claude Code install failed: ${err.message}`);
9634
9744
  return;
9635
9745
  }
9636
- const brewBinDir = dirname6(brewPath);
9746
+ const brewBinDir = dirname7(brewPath);
9637
9747
  if (!process.env.PATH?.split(":").includes(brewBinDir)) {
9638
9748
  process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
9639
9749
  }
@@ -10071,7 +10181,7 @@ function ensureEvalEmptyMcpConfig() {
10071
10181
  } catch {
10072
10182
  }
10073
10183
  const p = join23(dir, ".eval-empty-mcp.json");
10074
- writeFileSync11(p, JSON.stringify({ mcpServers: {} }));
10184
+ writeFileSync12(p, JSON.stringify({ mcpServers: {} }));
10075
10185
  evalEmptyMcpConfigPath = p;
10076
10186
  return p;
10077
10187
  }
@@ -10292,7 +10402,7 @@ function parseSkillFrontmatter(content) {
10292
10402
  return out;
10293
10403
  }
10294
10404
  async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
10295
- const { readdirSync: readdirSync6, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync12 } = await import("fs");
10405
+ const { readdirSync: readdirSync6, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync13 } = await import("fs");
10296
10406
  const skillsDir = join23(configDir, codeName, "project", ".claude", "skills");
10297
10407
  const claudeMdPath = join23(configDir, codeName, "project", "CLAUDE.md");
10298
10408
  if (!ex(skillsDir) || !ex(claudeMdPath)) return;
@@ -10340,7 +10450,7 @@ ${SKILLS_INDEX_END}`;
10340
10450
  next = current.trimEnd() + "\n\n" + section + "\n";
10341
10451
  }
10342
10452
  if (next !== current) {
10343
- writeFileSync12(claudeMdPath, next, "utf-8");
10453
+ writeFileSync13(claudeMdPath, next, "utf-8");
10344
10454
  log2(`Refreshed skills index in CLAUDE.md for '${codeName}' (${entries.length} skills)`);
10345
10455
  }
10346
10456
  }
@@ -10361,7 +10471,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
10361
10471
  if (codeNames.length === 0) return;
10362
10472
  void (async () => {
10363
10473
  try {
10364
- const { collectDiagnostics } = await import("../persistent-session-WMQO3QKU.js");
10474
+ const { collectDiagnostics } = await import("../persistent-session-SZ5VHS4C.js");
10365
10475
  await api.post("/host/heartbeat", {
10366
10476
  host_id: hostId,
10367
10477
  agent_diagnostics: collectDiagnostics(codeNames)
@@ -10460,7 +10570,7 @@ async function pollCycle() {
10460
10570
  }
10461
10571
  try {
10462
10572
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
10463
- const { collectDiagnostics } = await import("../persistent-session-WMQO3QKU.js");
10573
+ const { collectDiagnostics } = await import("../persistent-session-SZ5VHS4C.js");
10464
10574
  const diagCodeNames = [...agentState.persistentSessionAgents];
10465
10575
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
10466
10576
  let tailscaleHostname;
@@ -10615,7 +10725,7 @@ async function pollCycle() {
10615
10725
  const {
10616
10726
  collectResponsivenessProbes,
10617
10727
  getResponsivenessIntervalMs
10618
- } = await import("../responsiveness-probe-TCTSHDH3.js");
10728
+ } = await import("../responsiveness-probe-2D64EQAU.js");
10619
10729
  const probeIntervalMs = getResponsivenessIntervalMs();
10620
10730
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
10621
10731
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -10647,7 +10757,7 @@ async function pollCycle() {
10647
10757
  collectResponsivenessProbes,
10648
10758
  livePendingInboundOldestAgeSeconds,
10649
10759
  parkPendingInbound
10650
- } = await import("../responsiveness-probe-TCTSHDH3.js");
10760
+ } = await import("../responsiveness-probe-2D64EQAU.js");
10651
10761
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-HYOOQV4A.js");
10652
10762
  const wedgeNow = /* @__PURE__ */ new Date();
10653
10763
  const liveAgents = agentState.persistentSessionAgents;
@@ -11517,11 +11627,11 @@ async function processAgent(agent, agentStates) {
11517
11627
  log(`${verb} '${agent.code_name}': ${fileNames}`);
11518
11628
  for (const file of changedFiles) {
11519
11629
  const filePath = join23(agentDir, file.relativePath);
11520
- mkdirSync10(dirname6(filePath), { recursive: true });
11630
+ mkdirSync10(dirname7(filePath), { recursive: true });
11521
11631
  if (file.relativePath === ".mcp.json") {
11522
11632
  safeWriteJsonAtomic(filePath, file.content, { mode: 384 });
11523
11633
  } else {
11524
- writeFileSync11(filePath, file.content);
11634
+ writeFileSync12(filePath, file.content);
11525
11635
  }
11526
11636
  }
11527
11637
  try {
@@ -12231,6 +12341,25 @@ async function processAgent(agent, agentStates) {
12231
12341
  }
12232
12342
  }
12233
12343
  }
12344
+ const currentIntIds = integrations.map((i) => i.definition_id);
12345
+ const prevIntIds = agentState.knownIntegrationMembership.get(agent.agent_id) ?? [];
12346
+ const prevIntSet = new Set(prevIntIds);
12347
+ const curIntSet = new Set(currentIntIds);
12348
+ const changedIntIds = Array.from(
12349
+ /* @__PURE__ */ new Set([
12350
+ ...currentIntIds.filter((id) => !prevIntSet.has(id)),
12351
+ // added
12352
+ ...prevIntIds.filter((id) => !curIntSet.has(id))
12353
+ // removed
12354
+ ])
12355
+ ).sort();
12356
+ if (changedIntIds.length > 0) {
12357
+ agentState.provisioningAttribution.set(agent.code_name, {
12358
+ key: changedIntIds.join("+"),
12359
+ at: Date.now()
12360
+ });
12361
+ }
12362
+ agentState.knownIntegrationMembership.set(agent.agent_id, currentIntIds);
12234
12363
  if (integrations.length > 0) {
12235
12364
  const intHash = computeIntegrationsHash(integrations);
12236
12365
  const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
@@ -13783,7 +13912,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
13783
13912
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
13784
13913
  void (async () => {
13785
13914
  try {
13786
- const { collectDiagnostics } = await import("../persistent-session-WMQO3QKU.js");
13915
+ const { collectDiagnostics } = await import("../persistent-session-SZ5VHS4C.js");
13787
13916
  await api.post("/host/heartbeat", {
13788
13917
  host_id: hostId,
13789
13918
  agent_diagnostics: collectDiagnostics([codeName])
@@ -13833,7 +13962,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
13833
13962
  }
13834
13963
  try {
13835
13964
  const hostId = await getHostId();
13836
- const { collectDiagnostics } = await import("../persistent-session-WMQO3QKU.js");
13965
+ const { collectDiagnostics } = await import("../persistent-session-SZ5VHS4C.js");
13837
13966
  await api.post("/host/heartbeat", {
13838
13967
  host_id: hostId,
13839
13968
  agent_diagnostics: collectDiagnostics([codeName])
@@ -14119,8 +14248,8 @@ async function processDirectChatMessage(agent, msg) {
14119
14248
  if (useDoorbell) {
14120
14249
  try {
14121
14250
  const doorbell = directChatDoorbellPath(agent.agentId, homedir12());
14122
- mkdirSync10(dirname6(doorbell), { recursive: true });
14123
- writeFileSync11(doorbell, String(Date.now()));
14251
+ mkdirSync10(dirname7(doorbell), { recursive: true });
14252
+ writeFileSync12(doorbell, String(Date.now()));
14124
14253
  log(`[direct-chat] Doorbell rung for '${agent.codeName}' (msg=${msg.id}) \u2014 in-session MCP will pull via the cursor`);
14125
14254
  return;
14126
14255
  } catch (err) {
@@ -14229,8 +14358,8 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
14229
14358
  if (run_id) openInjectedRunByCode.set(codeName, run_id);
14230
14359
  try {
14231
14360
  const doorbell = directChatDoorbellPath(agentId, homedir12());
14232
- mkdirSync10(dirname6(doorbell), { recursive: true });
14233
- writeFileSync11(doorbell, String(Date.now()));
14361
+ mkdirSync10(dirname7(doorbell), { recursive: true });
14362
+ writeFileSync12(doorbell, String(Date.now()));
14234
14363
  } catch (err) {
14235
14364
  log(`[kanban] doorbell ring failed for '${codeName}': ${err.message} (notice still queued)`);
14236
14365
  }
@@ -14331,7 +14460,7 @@ async function processClaudePairSessions(agents) {
14331
14460
  killPairSession,
14332
14461
  pairTmuxSession,
14333
14462
  finalizeClaudePairOnboarding
14334
- } = await import("../claude-pair-runtime-KO2HWC7E.js");
14463
+ } = await import("../claude-pair-runtime-LLUV4KX6.js");
14335
14464
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
14336
14465
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
14337
14466
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -14676,10 +14805,10 @@ ${mem.content}
14676
14805
  } catch {
14677
14806
  }
14678
14807
  if (existing === desired) continue;
14679
- writeFileSync11(filePath, desired);
14808
+ writeFileSync12(filePath, desired);
14680
14809
  overwritten++;
14681
14810
  } else {
14682
- writeFileSync11(filePath, desired);
14811
+ writeFileSync12(filePath, desired);
14683
14812
  written++;
14684
14813
  }
14685
14814
  }
@@ -15081,7 +15210,7 @@ function restartRunningChannelMcps(basenames) {
15081
15210
  function deployMcpAssets() {
15082
15211
  const targetDir = join23(homedir12(), ".augmented", "_mcp");
15083
15212
  mkdirSync10(targetDir, { recursive: true });
15084
- const moduleDir = dirname6(fileURLToPath(import.meta.url));
15213
+ const moduleDir = dirname7(fileURLToPath(import.meta.url));
15085
15214
  let mcpSourceDir = "";
15086
15215
  let dir = moduleDir;
15087
15216
  for (let i = 0; i < 6; i++) {
@@ -15090,7 +15219,7 @@ function deployMcpAssets() {
15090
15219
  mcpSourceDir = candidate;
15091
15220
  break;
15092
15221
  }
15093
- const parent = dirname6(dir);
15222
+ const parent = dirname7(dir);
15094
15223
  if (parent === dir) break;
15095
15224
  dir = parent;
15096
15225
  }
@@ -15201,7 +15330,7 @@ function deployMcpAssets() {
15201
15330
  if (!augServer) continue;
15202
15331
  augServer.command = "node";
15203
15332
  augServer.args = [localMcpPath];
15204
- writeFileSync11(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
15333
+ writeFileSync12(mcpJsonPath, JSON.stringify(mcpConfig, null, 2));
15205
15334
  log(`[manager] Patched ${entry.name}/${subdir}/.mcp.json: npx \u2192 node`);
15206
15335
  } catch {
15207
15336
  }