@integrity-labs/agt-cli 0.28.350 → 0.28.352

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-CBWLRSM5.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-WMQO3QKU.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-FCW6HWAR.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-KO2HWC7E.js.map
@@ -45,8 +45,9 @@ import {
45
45
  requireHost,
46
46
  resolveEffectivePinRaw,
47
47
  safeWriteJsonAtomic,
48
- setConfigHash
49
- } from "../chunk-LM2RJRAT.js";
48
+ setConfigHash,
49
+ toOpencodeModel
50
+ } from "../chunk-BERN3B42.js";
50
51
  import {
51
52
  getProjectDir as getProjectDir2,
52
53
  getReadyTasks,
@@ -137,7 +138,7 @@ import {
137
138
  takeZombieDetection,
138
139
  transcriptActivityAgeSeconds,
139
140
  writeEgressAllowlist
140
- } from "../chunk-EUDBJHMA.js";
141
+ } from "../chunk-ZALWFOHO.js";
141
142
  import {
142
143
  reapOrphanChannelMcps
143
144
  } from "../chunk-XWVM4KPK.js";
@@ -146,7 +147,7 @@ import {
146
147
  import { createHash as createHash14 } from "crypto";
147
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";
148
149
  import { execFileSync as syncExecFile } from "child_process";
149
- import { join as join23, dirname as dirname6 } from "path";
150
+ import { join as join23, dirname as dirname6, delimiter as pathDelimiter } from "path";
150
151
  import { homedir as homedir12 } from "os";
151
152
  import { fileURLToPath } from "url";
152
153
 
@@ -1250,12 +1251,25 @@ function parseResumeHealthResponse(raw) {
1250
1251
  // src/lib/model-change-respawn.ts
1251
1252
  function shouldRespawnForModelChange(input) {
1252
1253
  const { previousModel, primaryModel, framework, sessionHealthy } = input;
1253
- if (framework !== "claude-code") return false;
1254
+ if (framework !== "claude-code" && framework !== "opencode") return false;
1254
1255
  if (!sessionHealthy) return false;
1255
1256
  if (!previousModel) return false;
1256
1257
  if (!primaryModel) return false;
1257
1258
  return previousModel !== primaryModel;
1258
1259
  }
1260
+ function decideOpencodeModelRestart(input) {
1261
+ const { previousModel, primaryModel, provisionedModel, onDiskModel, sessionHealthy } = input;
1262
+ if (onDiskModel !== provisionedModel) {
1263
+ return { restart: false, recordModel: false };
1264
+ }
1265
+ const restart = shouldRespawnForModelChange({
1266
+ previousModel,
1267
+ primaryModel,
1268
+ framework: "opencode",
1269
+ sessionHealthy
1270
+ });
1271
+ return { restart, recordModel: true };
1272
+ }
1259
1273
 
1260
1274
  // src/lib/connectivity-probe-runner.ts
1261
1275
  var DEFAULT_INTERVAL_MS = 60 * 60 * 1e3;
@@ -5577,6 +5591,15 @@ function opencodeTmuxSession(codeName) {
5577
5591
  function opencodePaneLogPath(codeName) {
5578
5592
  return join20(homedir10(), ".augmented", codeName, "opencode-serve.log");
5579
5593
  }
5594
+ function readProvisionedOpencodeModel(agentDir) {
5595
+ try {
5596
+ const raw = readFileSync16(join20(agentDir, "provision", "opencode.json"), "utf-8");
5597
+ const parsed = JSON.parse(raw);
5598
+ return typeof parsed.model === "string" ? parsed.model : null;
5599
+ } catch {
5600
+ return null;
5601
+ }
5602
+ }
5580
5603
  function baseUrlFor(port) {
5581
5604
  return `http://127.0.0.1:${port}`;
5582
5605
  }
@@ -5737,6 +5760,21 @@ function getBridge(codeName, port, password) {
5737
5760
  bridges.set(codeName, { port, password, bridge });
5738
5761
  return bridge;
5739
5762
  }
5763
+ function stopOpencodeSession(codeName, log2) {
5764
+ const tmuxSession = opencodeTmuxSession(codeName);
5765
+ try {
5766
+ execSync(`tmux kill-session -t ${tmuxSession} 2>/dev/null`, { stdio: "ignore" });
5767
+ log2(`[opencode-session] stopped '${tmuxSession}' for '${codeName}'`);
5768
+ } catch {
5769
+ }
5770
+ bridges.delete(codeName);
5771
+ const session = sessions.get(codeName);
5772
+ if (session) {
5773
+ session.status = "stopped";
5774
+ session.port = null;
5775
+ session.password = null;
5776
+ }
5777
+ }
5740
5778
  function stripUndefined(env) {
5741
5779
  const out = {};
5742
5780
  for (const [k, v] of Object.entries(env)) if (v !== void 0) out[k] = v;
@@ -9263,6 +9301,7 @@ var registeredAgentsCache = /* @__PURE__ */ new Map();
9263
9301
  var agentFrameworkCache = /* @__PURE__ */ new Map();
9264
9302
  var migratedSecretStorage = /* @__PURE__ */ new Set();
9265
9303
  var frameworkBinaryChecked = /* @__PURE__ */ new Set();
9304
+ var frameworkBinaryInflight = /* @__PURE__ */ new Map();
9266
9305
  var agentRuntimeAuthenticated = false;
9267
9306
  var lastManagedSettingsStatus = null;
9268
9307
  function resolveAgentFramework(codeName) {
@@ -9303,7 +9342,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
9303
9342
  var lastVersionCheckAt = 0;
9304
9343
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
9305
9344
  var lastResponsivenessProbeAt = 0;
9306
- var agtCliVersion = true ? "0.28.350" : "dev";
9345
+ var agtCliVersion = true ? "0.28.352" : "dev";
9307
9346
  function resolveBrewPath(execFileSync2) {
9308
9347
  try {
9309
9348
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -9508,9 +9547,63 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
9508
9547
  return "write_failed";
9509
9548
  }
9510
9549
  }
9550
+ var OPENCODE_NPM_VERSION = "1.18.3";
9551
+ async function ensureOpencodeBinary() {
9552
+ const { execFileSync: execFileSync2 } = await import("child_process");
9553
+ const bin = process.env["AGT_OPENCODE_BIN"]?.trim() || "opencode";
9554
+ const probe = () => {
9555
+ try {
9556
+ execFileSync2(bin, ["--version"], { stdio: "ignore", timeout: 1e4 });
9557
+ return true;
9558
+ } catch {
9559
+ return false;
9560
+ }
9561
+ };
9562
+ if (probe()) return true;
9563
+ log("[framework-install] opencode binary not found - installing opencode-ai via npm...");
9564
+ try {
9565
+ const r = await runAsync("npm", ["install", "-g", `opencode-ai@${OPENCODE_NPM_VERSION}`], { timeout: 18e4 });
9566
+ if (r.code !== 0) {
9567
+ log(
9568
+ `[framework-install] opencode install failed (exit ${r.code}): ${(r.stderr || r.stdout).trim().slice(0, 300)} - install manually: npm i -g opencode-ai@${OPENCODE_NPM_VERSION}`
9569
+ );
9570
+ return false;
9571
+ }
9572
+ } catch (err) {
9573
+ log(`[framework-install] opencode install threw: ${err.message} - install manually: npm i -g opencode-ai@${OPENCODE_NPM_VERSION}`);
9574
+ return false;
9575
+ }
9576
+ try {
9577
+ const prefix = execFileSync2("npm", ["prefix", "-g"], { encoding: "utf-8", timeout: 1e4 }).trim();
9578
+ if (prefix) {
9579
+ const npmBin = join23(prefix, "bin");
9580
+ const current = (process.env.PATH ?? "").split(pathDelimiter);
9581
+ if (!current.includes(npmBin)) {
9582
+ process.env.PATH = [npmBin, ...current.filter(Boolean)].join(pathDelimiter);
9583
+ }
9584
+ }
9585
+ } catch {
9586
+ }
9587
+ if (!probe()) {
9588
+ log(`[framework-install] opencode installed but '${bin} --version' still fails to resolve - will retry next cycle`);
9589
+ return false;
9590
+ }
9591
+ log("[framework-install] opencode installed");
9592
+ return true;
9593
+ }
9511
9594
  async function ensureFrameworkBinary(frameworkId) {
9512
- if (frameworkId !== "claude-code") return;
9595
+ if (frameworkId !== "claude-code" && frameworkId !== "opencode") return;
9513
9596
  if (frameworkBinaryChecked.has(frameworkId)) return;
9597
+ if (frameworkId === "opencode") {
9598
+ const inflight = frameworkBinaryInflight.get(frameworkId);
9599
+ if (inflight) return inflight;
9600
+ const attempt = (async () => {
9601
+ const ok = await ensureOpencodeBinary();
9602
+ if (ok) frameworkBinaryChecked.add(frameworkId);
9603
+ })().finally(() => frameworkBinaryInflight.delete(frameworkId));
9604
+ frameworkBinaryInflight.set(frameworkId, attempt);
9605
+ return attempt;
9606
+ }
9514
9607
  frameworkBinaryChecked.add(frameworkId);
9515
9608
  lastManagedSettingsStatus = ensureClaudeManagedSettings();
9516
9609
  const { execFileSync: execFileSync2 } = await import("child_process");
@@ -10268,7 +10361,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
10268
10361
  if (codeNames.length === 0) return;
10269
10362
  void (async () => {
10270
10363
  try {
10271
- const { collectDiagnostics } = await import("../persistent-session-CBWLRSM5.js");
10364
+ const { collectDiagnostics } = await import("../persistent-session-WMQO3QKU.js");
10272
10365
  await api.post("/host/heartbeat", {
10273
10366
  host_id: hostId,
10274
10367
  agent_diagnostics: collectDiagnostics(codeNames)
@@ -10367,7 +10460,7 @@ async function pollCycle() {
10367
10460
  }
10368
10461
  try {
10369
10462
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
10370
- const { collectDiagnostics } = await import("../persistent-session-CBWLRSM5.js");
10463
+ const { collectDiagnostics } = await import("../persistent-session-WMQO3QKU.js");
10371
10464
  const diagCodeNames = [...agentState.persistentSessionAgents];
10372
10465
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
10373
10466
  let tailscaleHostname;
@@ -10522,7 +10615,7 @@ async function pollCycle() {
10522
10615
  const {
10523
10616
  collectResponsivenessProbes,
10524
10617
  getResponsivenessIntervalMs
10525
- } = await import("../responsiveness-probe-56WUFX3U.js");
10618
+ } = await import("../responsiveness-probe-TCTSHDH3.js");
10526
10619
  const probeIntervalMs = getResponsivenessIntervalMs();
10527
10620
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
10528
10621
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -10554,7 +10647,7 @@ async function pollCycle() {
10554
10647
  collectResponsivenessProbes,
10555
10648
  livePendingInboundOldestAgeSeconds,
10556
10649
  parkPendingInbound
10557
- } = await import("../responsiveness-probe-56WUFX3U.js");
10650
+ } = await import("../responsiveness-probe-TCTSHDH3.js");
10558
10651
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-HYOOQV4A.js");
10559
10652
  const wedgeNow = /* @__PURE__ */ new Date();
10560
10653
  const liveAgents = agentState.persistentSessionAgents;
@@ -11529,6 +11622,28 @@ async function processAgent(agent, agentStates) {
11529
11622
  }
11530
11623
  }
11531
11624
  agentState.knownModels.set(agent.agent_id, primaryModel);
11625
+ } else if (primaryModel && frameworkId === "opencode") {
11626
+ const previousModel = agentState.knownModels.get(agent.agent_id);
11627
+ const provisionedModel = toOpencodeModel(primaryModel);
11628
+ const onDiskModel = readProvisionedOpencodeModel(getFramework("opencode").getAgentDir(agent.code_name));
11629
+ const { restart, recordModel } = decideOpencodeModelRestart({
11630
+ previousModel,
11631
+ primaryModel,
11632
+ provisionedModel,
11633
+ onDiskModel,
11634
+ sessionHealthy: isOpencodeSessionHealthy(agent.code_name)
11635
+ });
11636
+ if (restart) {
11637
+ log(
11638
+ `[hot-reload] opencode model changed for '${agent.code_name}': ${previousModel} -> ${primaryModel} - restarting serve`
11639
+ );
11640
+ stopOpencodeSession(agent.code_name, log);
11641
+ } else if (previousModel && previousModel !== primaryModel && onDiskModel !== provisionedModel) {
11642
+ log(
11643
+ `[hot-reload] opencode model change for '${agent.code_name}' deferred: opencode.json shows '${onDiskModel}' not '${provisionedModel}' (provision not yet applied) - retrying next poll`
11644
+ );
11645
+ }
11646
+ if (recordModel) agentState.knownModels.set(agent.agent_id, primaryModel);
11532
11647
  }
11533
11648
  let lastDriftCheckAt = now;
11534
11649
  const written = agentState.writtenHashes.get(agent.agent_id);
@@ -13668,7 +13783,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
13668
13783
  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}`));
13669
13784
  void (async () => {
13670
13785
  try {
13671
- const { collectDiagnostics } = await import("../persistent-session-CBWLRSM5.js");
13786
+ const { collectDiagnostics } = await import("../persistent-session-WMQO3QKU.js");
13672
13787
  await api.post("/host/heartbeat", {
13673
13788
  host_id: hostId,
13674
13789
  agent_diagnostics: collectDiagnostics([codeName])
@@ -13718,7 +13833,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
13718
13833
  }
13719
13834
  try {
13720
13835
  const hostId = await getHostId();
13721
- const { collectDiagnostics } = await import("../persistent-session-CBWLRSM5.js");
13836
+ const { collectDiagnostics } = await import("../persistent-session-WMQO3QKU.js");
13722
13837
  await api.post("/host/heartbeat", {
13723
13838
  host_id: hostId,
13724
13839
  agent_diagnostics: collectDiagnostics([codeName])
@@ -14216,7 +14331,7 @@ async function processClaudePairSessions(agents) {
14216
14331
  killPairSession,
14217
14332
  pairTmuxSession,
14218
14333
  finalizeClaudePairOnboarding
14219
- } = await import("../claude-pair-runtime-FCW6HWAR.js");
14334
+ } = await import("../claude-pair-runtime-KO2HWC7E.js");
14220
14335
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
14221
14336
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
14222
14337
  const killed = await killPairSession(pairTmuxSession(pairId));