@integrity-labs/agt-cli 0.28.413 → 0.28.414

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
@@ -40,7 +40,7 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-GRXN3X33.js";
43
+ } from "../chunk-UI5WQACL.js";
44
44
  import {
45
45
  AnchorSessionClient,
46
46
  CHANNEL_REGISTRY,
@@ -4829,7 +4829,7 @@ import { execFileSync, execSync } from "child_process";
4829
4829
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4830
4830
  import chalk18 from "chalk";
4831
4831
  import ora16 from "ora";
4832
- var cliVersion = true ? "0.28.413" : "dev";
4832
+ var cliVersion = true ? "0.28.414" : "dev";
4833
4833
  async function fetchLatestVersion() {
4834
4834
  const host2 = getHost();
4835
4835
  if (!host2) return null;
@@ -6001,7 +6001,7 @@ function handleError(err) {
6001
6001
  }
6002
6002
 
6003
6003
  // src/bin/agt.ts
6004
- var cliVersion2 = true ? "0.28.413" : "dev";
6004
+ var cliVersion2 = true ? "0.28.414" : "dev";
6005
6005
  var program = new Command();
6006
6006
  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");
6007
6007
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -6247,7 +6247,7 @@ function requireHost() {
6247
6247
  }
6248
6248
 
6249
6249
  // src/lib/api-client.ts
6250
- var agtCliVersion = true ? "0.28.413" : "dev";
6250
+ var agtCliVersion = true ? "0.28.414" : "dev";
6251
6251
  var lastConfigHash = null;
6252
6252
  function setConfigHash(hash) {
6253
6253
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8751,4 +8751,4 @@ export {
8751
8751
  managerInstallSystemUnitCommand,
8752
8752
  managerUninstallSystemUnitCommand
8753
8753
  };
8754
- //# sourceMappingURL=chunk-GRXN3X33.js.map
8754
+ //# sourceMappingURL=chunk-UI5WQACL.js.map
@@ -45,7 +45,7 @@ import {
45
45
  resolveEffectivePinRaw,
46
46
  safeWriteJsonAtomic,
47
47
  setConfigHash
48
- } from "../chunk-GRXN3X33.js";
48
+ } from "../chunk-UI5WQACL.js";
49
49
  import {
50
50
  getProjectDir as getProjectDir2,
51
51
  getReadyTasks,
@@ -154,7 +154,7 @@ import {
154
154
  } from "../chunk-XWVM4KPK.js";
155
155
 
156
156
  // src/lib/manager-worker.ts
157
- import { createHash as createHash14 } from "crypto";
157
+ import { createHash as createHash15 } from "crypto";
158
158
  import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as mkdirSync10, existsSync as existsSync11, rmSync as rmSync5, readdirSync as readdirSync6, statSync as statSync4, copyFileSync } from "fs";
159
159
  import { execFileSync as syncExecFile } from "child_process";
160
160
  import { join as join22, dirname as dirname7, delimiter as pathDelimiter } from "path";
@@ -1370,6 +1370,40 @@ function stopAgentRuntime(codeName, reason, log2, deps) {
1370
1370
  });
1371
1371
  }
1372
1372
 
1373
+ // src/lib/opencode-credential-fingerprint.ts
1374
+ import { createHash as createHash4 } from "crypto";
1375
+ var FINGERPRINT_LENGTH = 16;
1376
+ var ABSENT = "none";
1377
+ function fingerprintOf(secret) {
1378
+ if (!secret) return ABSENT;
1379
+ return createHash4("sha256").update(secret, "utf8").digest("hex").slice(0, FINGERPRINT_LENGTH);
1380
+ }
1381
+ function opencodeCredentialFingerprint(inputs) {
1382
+ const openRouter = inputs.openRouterToken ? inputs.openRouterFingerprint || fingerprintOf(inputs.openRouterToken) : ABSENT;
1383
+ return `or:${openRouter}|an:${fingerprintOf(inputs.anthropicKey)}`;
1384
+ }
1385
+ function slots(fingerprint3) {
1386
+ const out = {};
1387
+ for (const part of fingerprint3.split("|")) {
1388
+ const idx = part.indexOf(":");
1389
+ if (idx > 0) out[part.slice(0, idx)] = part.slice(idx + 1);
1390
+ }
1391
+ return out;
1392
+ }
1393
+ function shouldRestartForCredentialChange(recorded, current) {
1394
+ if (recorded === current) return false;
1395
+ const before = slots(recorded);
1396
+ const after = slots(current);
1397
+ for (const key of /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])) {
1398
+ const was = before[key] ?? ABSENT;
1399
+ const now = after[key] ?? ABSENT;
1400
+ if (was === now) continue;
1401
+ if (now === ABSENT) continue;
1402
+ return true;
1403
+ }
1404
+ return false;
1405
+ }
1406
+
1373
1407
  // src/lib/connectivity-probe-runner.ts
1374
1408
  var DEFAULT_INTERVAL_MS = 60 * 60 * 1e3;
1375
1409
  var DEFAULT_MAX_PER_RUN = 25;
@@ -1821,7 +1855,7 @@ function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
1821
1855
  }
1822
1856
 
1823
1857
  // ../../packages/core/dist/host-config/capture.js
1824
- import { createHash as createHash4 } from "crypto";
1858
+ import { createHash as createHash5 } from "crypto";
1825
1859
  var NON_SECRET_ENV_GATES = [
1826
1860
  "AGT_MEMORY_EXTRACTION_ENABLED",
1827
1861
  "AGT_CHANNEL_REPLAY_ENABLED",
@@ -3439,10 +3473,10 @@ function parseExpiresAt(raw) {
3439
3473
  }
3440
3474
 
3441
3475
  // src/lib/channel-config-hash.ts
3442
- import { createHash as createHash5 } from "crypto";
3476
+ import { createHash as createHash6 } from "crypto";
3443
3477
  var CHANNEL_WRITE_VERSION = 9;
3444
3478
  function computeChannelConfigHash(input) {
3445
- return createHash5("sha256").update(
3479
+ return createHash6("sha256").update(
3446
3480
  canonicalJson({
3447
3481
  writeVersion: CHANNEL_WRITE_VERSION,
3448
3482
  cliVersion: input.cliVersion,
@@ -4513,7 +4547,7 @@ function saveKanbanNudgeState(source, configDir) {
4513
4547
  }
4514
4548
 
4515
4549
  // src/lib/manager/kanban/notify.ts
4516
- import { createHash as createHash6 } from "crypto";
4550
+ import { createHash as createHash7 } from "crypto";
4517
4551
  async function enqueueKanbanNotice(opts) {
4518
4552
  try {
4519
4553
  const res = await api.post(
@@ -4528,7 +4562,7 @@ async function enqueueKanbanNotice(opts) {
4528
4562
  return res.ok === true;
4529
4563
  } catch (err) {
4530
4564
  const errText = err instanceof Error ? err.message : String(err);
4531
- const errId = createHash6("sha256").update(errText).digest("hex").slice(0, 12);
4565
+ const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
4532
4566
  log(`[kanban] notice enqueue failed for agent_id=${opts.agentId} error_id=${errId}`);
4533
4567
  return false;
4534
4568
  }
@@ -4543,7 +4577,7 @@ async function cancelKanbanNotice(agentId) {
4543
4577
  return typeof res.cancelled === "number" ? res.cancelled : 0;
4544
4578
  } catch (err) {
4545
4579
  const errText = err instanceof Error ? err.message : String(err);
4546
- const errId = createHash6("sha256").update(errText).digest("hex").slice(0, 12);
4580
+ const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
4547
4581
  log(`[kanban] notice cancel failed for agent_id=${agentId} error_id=${errId}`);
4548
4582
  return null;
4549
4583
  }
@@ -4949,7 +4983,7 @@ function deriveScheduledTaskNotify(task) {
4949
4983
  }
4950
4984
 
4951
4985
  // src/lib/manager/scheduler/runs.ts
4952
- import { createHash as createHash7 } from "crypto";
4986
+ import { createHash as createHash8 } from "crypto";
4953
4987
  async function startRun(opts) {
4954
4988
  try {
4955
4989
  const res = await api.post(
@@ -4964,7 +4998,7 @@ async function startRun(opts) {
4964
4998
  };
4965
4999
  } catch (err) {
4966
5000
  const errText = err instanceof Error ? err.message : String(err);
4967
- const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
5001
+ const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
4968
5002
  log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
4969
5003
  return { run_id: null, kanban_item_id: null };
4970
5004
  }
@@ -4981,7 +5015,7 @@ async function finishRun(runId, outcome, options = {}) {
4981
5015
  });
4982
5016
  } catch (err) {
4983
5017
  const errText = err instanceof Error ? err.message : String(err);
4984
- const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
5018
+ const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
4985
5019
  log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
4986
5020
  }
4987
5021
  }
@@ -4998,7 +5032,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
4998
5032
  return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
4999
5033
  } catch (err) {
5000
5034
  const errText = err instanceof Error ? err.message : String(err);
5001
- const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
5035
+ const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
5002
5036
  log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
5003
5037
  return [];
5004
5038
  }
@@ -5047,13 +5081,13 @@ function closeScheduledRunsForCode(codeName, outcome, reason) {
5047
5081
  }
5048
5082
 
5049
5083
  // src/lib/manager/scheduler/kanban-route.ts
5050
- import { createHash as createHash9 } from "crypto";
5084
+ import { createHash as createHash10 } from "crypto";
5051
5085
  import { writeFileSync as writeFileSync8, renameSync, mkdirSync as mkdirSync6 } from "fs";
5052
5086
  import { homedir as homedir7 } from "os";
5053
5087
  import { join as join17, dirname as dirname5 } from "path";
5054
5088
 
5055
5089
  // src/lib/manager/scheduler/notify.ts
5056
- import { createHash as createHash8 } from "crypto";
5090
+ import { createHash as createHash9 } from "crypto";
5057
5091
  async function enqueueScheduledTaskNotice(opts) {
5058
5092
  try {
5059
5093
  const res = await api.post(
@@ -5069,7 +5103,7 @@ async function enqueueScheduledTaskNotice(opts) {
5069
5103
  return res.ok === true;
5070
5104
  } catch (err) {
5071
5105
  const errText = err instanceof Error ? err.message : String(err);
5072
- const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
5106
+ const errId = createHash9("sha256").update(errText).digest("hex").slice(0, 12);
5073
5107
  log(
5074
5108
  `[scheduled-kanban] notice enqueue failed for agent_id=${opts.agentId} task_id=${opts.taskId} error_id=${errId}`
5075
5109
  );
@@ -5503,24 +5537,24 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
5503
5537
  const assertion = parseDeliverAssertion(rawOutput);
5504
5538
  if (!assertion.deliver) {
5505
5539
  const trimmed = (rawOutput ?? "").trim();
5506
- const outputHash = trimmed.length === 0 ? "empty" : createHash9("sha256").update(trimmed).digest("hex").slice(0, 12);
5540
+ const outputHash = trimmed.length === 0 ? "empty" : createHash10("sha256").update(trimmed).digest("hex").slice(0, 12);
5507
5541
  log(`[claude-scheduler] Suppressed by delivery_policy=conditional for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 ${assertion.vacuous ? "deliver marker had a vacuous reason" : "no deliver marker"}; output_len=${trimmed.length} output_hash=${outputHash}`);
5508
5542
  if (delivery?.mode === "announce" && delivery.to) {
5509
5543
  await reportDeliveryStatus(agentId, delivery.taskId, { status: "skipped", error_code: "SUPPRESSED_BY_POLICY" });
5510
5544
  }
5511
5545
  return { ok: true };
5512
5546
  }
5513
- const reasonHash = createHash9("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
5547
+ const reasonHash = createHash10("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
5514
5548
  log(`[claude-scheduler] Delivering conditional run for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 agent asserted a concrete trigger (reason_len=${(assertion.reason ?? "").length} reason_hash=${reasonHash})`);
5515
5549
  rawOutput = assertion.deliverable;
5516
5550
  }
5517
5551
  const classification = classifyOutput(rawOutput);
5518
5552
  if (classification.action === "suppress") {
5519
5553
  const trimmed = (rawOutput ?? "").trim();
5520
- const outputHash = trimmed.length === 0 ? "empty" : createHash9("sha256").update(trimmed).digest("hex").slice(0, 12);
5554
+ const outputHash = trimmed.length === 0 ? "empty" : createHash10("sha256").update(trimmed).digest("hex").slice(0, 12);
5521
5555
  log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output_len=${trimmed.length} output_hash=${outputHash}`);
5522
5556
  if (classification.suppressedNotes) {
5523
- const notesHash = createHash9("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
5557
+ const notesHash = createHash10("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
5524
5558
  log(`[claude-scheduler] Suppressed notes for '${codeName}' (task=${delivery?.taskId ?? "n/a"}) \u2014 notes_len=${classification.suppressedNotes.length} notes_hash=${notesHash}`);
5525
5559
  }
5526
5560
  if (delivery?.mode === "announce" && delivery.to) {
@@ -5586,7 +5620,7 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
5586
5620
  }
5587
5621
 
5588
5622
  // src/lib/manager/scheduler/execution.ts
5589
- import { createHash as createHash10 } from "crypto";
5623
+ import { createHash as createHash11 } from "crypto";
5590
5624
  import { homedir as homedir8 } from "os";
5591
5625
  import { join as join18 } from "path";
5592
5626
  function claudePidFilePath() {
@@ -5610,10 +5644,10 @@ function unregisterClaudeSpawn(pid) {
5610
5644
  }
5611
5645
  async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData) {
5612
5646
  const codeName = agent.code_name;
5613
- const stableTasksHash = createHash10("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
5614
- const boardHash = boardItems.length > 0 ? createHash10("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
5647
+ const stableTasksHash = createHash11("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
5648
+ const boardHash = boardItems.length > 0 ? createHash11("sha256").update(JSON.stringify(boardItems.map((b) => ({ id: b.id, title: b.title, status: b.status, priority: b.priority, deliverable: b.deliverable })))).digest("hex").slice(0, 16) : "empty";
5615
5649
  const resolvedModels = resolveModelChain(refreshData);
5616
- const modelsHash = createHash10("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
5650
+ const modelsHash = createHash11("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
5617
5651
  const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
5618
5652
  const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
5619
5653
  if (combinedHash !== prevHash) {
@@ -5651,7 +5685,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
5651
5685
  }
5652
5686
 
5653
5687
  // src/lib/opencode-slack-ingest.ts
5654
- import { createHash as createHash11 } from "crypto";
5688
+ import { createHash as createHash12 } from "crypto";
5655
5689
 
5656
5690
  // ../../packages/core/dist/channels/slack-rich-text.js
5657
5691
  var MAX_DEPTH = 12;
@@ -6587,7 +6621,7 @@ function startSlackIngest(config2) {
6587
6621
  // src/lib/opencode-slack-ingest.ts
6588
6622
  var ingests = /* @__PURE__ */ new Map();
6589
6623
  function fingerprint(params) {
6590
- return createHash11("sha256").update(
6624
+ return createHash12("sha256").update(
6591
6625
  JSON.stringify({
6592
6626
  appToken: params.appToken,
6593
6627
  botToken: params.botToken,
@@ -6668,7 +6702,7 @@ function stopAllOpencodeSlackIngests(log2) {
6668
6702
  }
6669
6703
 
6670
6704
  // src/lib/manager/opencode-scheduler.ts
6671
- import { createHash as createHash12 } from "crypto";
6705
+ import { createHash as createHash13 } from "crypto";
6672
6706
  var MAX_OPENCODE_SCHED_CONCURRENCY = 2;
6673
6707
  var opencodeSchedulerStates = /* @__PURE__ */ new Map();
6674
6708
  var inFlightOpencodeTasks = /* @__PURE__ */ new Set();
@@ -6682,7 +6716,7 @@ function shouldDeliver(task, reply) {
6682
6716
  }
6683
6717
  async function syncAndCheckOpencodeScheduler(agent, tasks, refreshData) {
6684
6718
  const codeName = agent.code_name;
6685
- const tasksHash = createHash12("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
6719
+ const tasksHash = createHash13("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
6686
6720
  if (knownOpencodeTaskHashes.get(agent.agent_id) !== tasksHash) {
6687
6721
  const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
6688
6722
  const state8 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
@@ -6760,7 +6794,7 @@ async function fireOpencodeScheduledTask(agent, task) {
6760
6794
  }
6761
6795
 
6762
6796
  // src/lib/opencode-telegram-ingest.ts
6763
- import { createHash as createHash13 } from "crypto";
6797
+ import { createHash as createHash14 } from "crypto";
6764
6798
  import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync15, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync9 } from "fs";
6765
6799
  import { randomUUID } from "crypto";
6766
6800
  import { join as join19 } from "path";
@@ -7296,7 +7330,7 @@ function anySignal(signals) {
7296
7330
  // src/lib/opencode-telegram-ingest.ts
7297
7331
  var ingests2 = /* @__PURE__ */ new Map();
7298
7332
  function fingerprint2(params) {
7299
- return createHash13("sha256").update(
7333
+ return createHash14("sha256").update(
7300
7334
  JSON.stringify({
7301
7335
  botToken: params.botToken,
7302
7336
  allowedChats: [...params.allowedChats].sort(),
@@ -9047,7 +9081,7 @@ var sessionLaunchManagedStructure = /* @__PURE__ */ new Map();
9047
9081
  function projectMcpHash(_codeName, projectDir) {
9048
9082
  try {
9049
9083
  const raw = readFileSync18(join22(projectDir, ".mcp.json"), "utf-8");
9050
- return createHash14("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
9084
+ return createHash15("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
9051
9085
  } catch {
9052
9086
  return null;
9053
9087
  }
@@ -9393,6 +9427,7 @@ function clearAgentCaches(agentId, codeName) {
9393
9427
  stopOpencodeSlackIngest(codeName, log);
9394
9428
  stopOpencodeTelegramIngest(codeName, log);
9395
9429
  agentFrameworkCache.delete(codeName);
9430
+ opencodeCredentialFingerprintBySession.delete(codeName);
9396
9431
  kanbanBoardCache.delete(codeName);
9397
9432
  clearKanbanNudgeState(codeName);
9398
9433
  notifyBoardCache.delete(codeName);
@@ -9421,7 +9456,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
9421
9456
  var lastVersionCheckAt = 0;
9422
9457
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
9423
9458
  var lastResponsivenessProbeAt = 0;
9424
- var agtCliVersion = true ? "0.28.413" : "dev";
9459
+ var agtCliVersion = true ? "0.28.414" : "dev";
9425
9460
  function resolveBrewPath(execFileSync2) {
9426
9461
  try {
9427
9462
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -10706,7 +10741,7 @@ async function pollCycle() {
10706
10741
  claudeAuth = await detectClaudeAuth();
10707
10742
  } catch (err) {
10708
10743
  const errText = err instanceof Error ? err.message : String(err);
10709
- const errId = createHash14("sha256").update(errText).digest("hex").slice(0, 12);
10744
+ const errId = createHash15("sha256").update(errText).digest("hex").slice(0, 12);
10710
10745
  log(`Claude auth detection failed (error_id=${errId})`);
10711
10746
  }
10712
10747
  const hostHasClaudeCode = state6.agents.some(
@@ -12127,7 +12162,7 @@ async function processAgent(agent, agentStates) {
12127
12162
  const behaviourSubset = extractMsTeamsBehaviourSubset(
12128
12163
  msteamsEntry?.config
12129
12164
  );
12130
- const behaviourHash = createHash14("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
12165
+ const behaviourHash = createHash15("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
12131
12166
  const prevBehaviourHash = agentState.knownMsTeamsBehaviourHashes.get(agent.agent_id);
12132
12167
  const msteamsBehaviourRestrictive = isMsTeamsBehaviourRestrictive(behaviourSubset);
12133
12168
  const behaviourDecision = decideSenderPolicyRestart({
@@ -12183,7 +12218,7 @@ async function processAgent(agent, agentStates) {
12183
12218
  const slackBehaviourSubset = extractSlackBehaviourSubset(
12184
12219
  slackEntry?.config
12185
12220
  );
12186
- const slackBehaviourHash = createHash14("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
12221
+ const slackBehaviourHash = createHash15("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
12187
12222
  const prevSlackBehaviourHash = agentState.knownSlackBehaviourHashes.get(agent.agent_id);
12188
12223
  const slackBehaviourRestrictive = isSlackBehaviourRestrictive(slackBehaviourSubset);
12189
12224
  const slackBehaviourDecision = decideSenderPolicyRestart({
@@ -12616,10 +12651,10 @@ async function processAgent(agent, agentStates) {
12616
12651
  desiredEntries.push({ serverId, url, headers: mcpHeaders, name: tk.toolkit_name });
12617
12652
  }
12618
12653
  const hashBasis = desiredEntries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => {
12619
- const headersHash = createHash14("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
12654
+ const headersHash = createHash15("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
12620
12655
  return `${e.serverId}|${e.url}|${headersHash}`;
12621
12656
  }).join("\n");
12622
- const mcpHash = createHash14("sha256").update(hashBasis).digest("hex").slice(0, 16);
12657
+ const mcpHash = createHash15("sha256").update(hashBasis).digest("hex").slice(0, 16);
12623
12658
  const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
12624
12659
  const structureHash = managedMcpStructureHash(desiredEntries);
12625
12660
  const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
@@ -12634,7 +12669,7 @@ async function processAgent(agent, agentStates) {
12634
12669
  if (mcpHash !== prevMcpHash) {
12635
12670
  for (const e of desiredEntries) {
12636
12671
  frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
12637
- const urlHash = createHash14("sha256").update(e.url).digest("hex").slice(0, 12);
12672
+ const urlHash = createHash15("sha256").update(e.url).digest("hex").slice(0, 12);
12638
12673
  log(`[managed-toolkit] ${agent.code_name}: wrote '${e.name}' (serverId=${e.serverId}, url_hash=${urlHash})`);
12639
12674
  }
12640
12675
  if (frameworkAdapter.removeMcpServer && frameworkAdapter.readMcpServers) {
@@ -12736,7 +12771,7 @@ async function processAgent(agent, agentStates) {
12736
12771
  if (frameworkAdapter.installSkillFiles) {
12737
12772
  const currentIntegrationSkillIds = /* @__PURE__ */ new Set();
12738
12773
  const installedIntegrationSkills = [];
12739
- const { createHash: createHash15 } = await import("crypto");
12774
+ const { createHash: createHash16 } = await import("crypto");
12740
12775
  const refreshAny = refreshData;
12741
12776
  const contexts = refreshAny.integration_contexts ?? refreshAny.plugin_contexts ?? [];
12742
12777
  const contextBySlug = /* @__PURE__ */ new Map();
@@ -12765,7 +12800,7 @@ async function processAgent(agent, agentStates) {
12765
12800
  )
12766
12801
  }));
12767
12802
  const bundle = buildIntegrationBundle(renderedScopes);
12768
- const contentHash = createHash15("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
12803
+ const contentHash = createHash16("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
12769
12804
  const hashKey = `plugin-skill:${agent.agent_id}:${integrationSkillId}`;
12770
12805
  if (agentState.knownSkillHashes.get(hashKey) === contentHash) continue;
12771
12806
  frameworkAdapter.installSkillFiles(agent.code_name, integrationSkillId, bundle.files);
@@ -12832,7 +12867,7 @@ async function processAgent(agent, agentStates) {
12832
12867
  const plan = planGlobalSkillSync(
12833
12868
  [...globalSkillsPayload ?? [], ...sharedSkillsPayload ?? []],
12834
12869
  prevIds,
12835
- (content) => createHash15("sha256").update(content).digest("hex").slice(0, 12),
12870
+ (content) => createHash16("sha256").update(content).digest("hex").slice(0, 12),
12836
12871
  (skillId) => agentState.knownSkillHashes.get(`global-skill:${agent.agent_id}:${skillId}`),
12837
12872
  { desiredResolved }
12838
12873
  );
@@ -12883,7 +12918,7 @@ async function processAgent(agent, agentStates) {
12883
12918
  const slug = hook.integration_slug ?? hook.plugin_slug;
12884
12919
  if (!slug) continue;
12885
12920
  try {
12886
- const scriptHash = createHash15("sha256").update(hook.script).digest("hex").slice(0, 12);
12921
+ const scriptHash = createHash16("sha256").update(hook.script).digest("hex").slice(0, 12);
12887
12922
  const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
12888
12923
  if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
12889
12924
  const result = await frameworkAdapter.executePluginHook({
@@ -12898,9 +12933,9 @@ async function processAgent(agent, agentStates) {
12898
12933
  } else if (result.timedOut) {
12899
12934
  log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
12900
12935
  } else {
12901
- const stderrHash = createHash15("sha256").update(result.stderr).digest("hex").slice(0, 12);
12936
+ const stderrHash = createHash16("sha256").update(result.stderr).digest("hex").slice(0, 12);
12902
12937
  const missingCmd = result.exitCode === 127 ? extractCommandNotFound(result.stderr) : null;
12903
- const missingCmdHash = missingCmd ? createHash15("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
12938
+ const missingCmdHash = missingCmd ? createHash16("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
12904
12939
  log(
12905
12940
  `Integration hook on_install '${slug}' exited ${result.exitCode} for '${agent.code_name}' ` + (missingCmdHash ? `[missing_command_hash=${missingCmdHash}] ` : "") + `[stderr_hash=${stderrHash} stderr_len=${result.stderr.length}]`
12906
12941
  );
@@ -13499,6 +13534,7 @@ var lastModelApiErrorSig = /* @__PURE__ */ new Map();
13499
13534
  var DAY_ROLLOVER_FORCE_GRACE_MIN = 30;
13500
13535
  var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
13501
13536
  var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
13537
+ var opencodeCredentialFingerprintBySession = /* @__PURE__ */ new Map();
13502
13538
  var egressAllowlistBySession = /* @__PURE__ */ new Map();
13503
13539
  function deriveEgressAllowlist(toolsRaw) {
13504
13540
  return buildEgressAllowlist(
@@ -13508,16 +13544,31 @@ function deriveEgressAllowlist(toolsRaw) {
13508
13544
  var egressAllowlistEqual = (a, b) => a.length === b.length && a.every((d, i) => d === b[i]);
13509
13545
  async function ensureOpencodeRuntime(agent, refreshData, agentTimezone) {
13510
13546
  const codeName = agent.code_name;
13547
+ const openRouterRaw = refreshData.openrouter ?? null;
13548
+ const anthropicRaw = refreshData.anthropic ?? null;
13549
+ const credentialFingerprint = opencodeCredentialFingerprint({
13550
+ openRouterToken: openRouterRaw?.auth_token,
13551
+ openRouterFingerprint: openRouterRaw?.fingerprint,
13552
+ anthropicKey: anthropicRaw?.api_key
13553
+ });
13511
13554
  if (isOpencodeSessionHealthy(codeName)) {
13512
- await ensureOpencodeSlackIngest({ codeName, agentId: agent.agent_id, log });
13513
- await ensureOpencodeTelegramIngest({ codeName, agentId: agent.agent_id, log });
13514
- return { decision: "healthy", spawnAttempted: false, sessionHealthyAfter: true };
13555
+ const recorded = opencodeCredentialFingerprintBySession.get(codeName);
13556
+ if (recorded && shouldRestartForCredentialChange(recorded, credentialFingerprint)) {
13557
+ log(
13558
+ `[opencode-session] Provider credential rotated for '${codeName}' (${recorded} \u2192 ${credentialFingerprint}) \u2014 restarting serve`
13559
+ );
13560
+ stopOpencodeSession(codeName, log);
13561
+ opencodeCredentialFingerprintBySession.delete(codeName);
13562
+ } else {
13563
+ await ensureOpencodeSlackIngest({ codeName, agentId: agent.agent_id, log });
13564
+ await ensureOpencodeTelegramIngest({ codeName, agentId: agent.agent_id, log });
13565
+ if (!recorded) opencodeCredentialFingerprintBySession.set(codeName, credentialFingerprint);
13566
+ return { decision: "healthy", spawnAttempted: false, sessionHealthyAfter: true };
13567
+ }
13515
13568
  }
13516
13569
  stopOpencodeSlackIngest(codeName, log);
13517
13570
  stopOpencodeTelegramIngest(codeName, log);
13518
13571
  const opencodeProjectDir = join22(getFramework("opencode").getAgentDir(codeName), "provision");
13519
- const openRouterRaw = refreshData.openrouter ?? null;
13520
- const anthropicRaw = refreshData.anthropic ?? null;
13521
13572
  const serveEnv = {
13522
13573
  AGT_HOST: requireHost(),
13523
13574
  AGT_API_KEY: getApiKey() ?? void 0,
@@ -13549,6 +13600,7 @@ async function ensureOpencodeRuntime(agent, refreshData, agentTimezone) {
13549
13600
  detail: tail ? `opencode spawn failed: ${tail.slice(0, 200)}` : "opencode spawn failed"
13550
13601
  };
13551
13602
  }
13603
+ opencodeCredentialFingerprintBySession.set(codeName, credentialFingerprint);
13552
13604
  return {
13553
13605
  decision: "spawn",
13554
13606
  spawnAttempted,
@@ -13718,7 +13770,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
13718
13770
  const ctx = getLastFailureContext(codeName);
13719
13771
  const recovery = prepareForRespawn(codeName);
13720
13772
  const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
13721
- ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash14("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
13773
+ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash15("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
13722
13774
  const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
13723
13775
  const recoverySummary = recovery ? `; recovery=${recovery}` : "";
13724
13776
  log(
@@ -13732,7 +13784,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash14("sha256")
13732
13784
  );
13733
13785
  getHostId().then((hostId) => {
13734
13786
  if (!hostId) return;
13735
- const paneTailHash = zombie.paneTail ? `sha256:${createHash14("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
13787
+ const paneTailHash = zombie.paneTail ? `sha256:${createHash15("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
13736
13788
  return api.post("/host/events", {
13737
13789
  host_id: hostId,
13738
13790
  agent_code_name: codeName,
@@ -13881,7 +13933,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash14("sha256")
13881
13933
  if (!claudeAuthTupleBySession.has(codeName)) {
13882
13934
  claudeAuthTupleBySession.set(codeName, currentAuthTuple);
13883
13935
  }
13884
- const stableTasksHash = createHash14("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
13936
+ const stableTasksHash = createHash15("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
13885
13937
  const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
13886
13938
  if (stableTasksHash !== prevHash) {
13887
13939
  const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
@@ -14882,7 +14934,7 @@ async function syncMemories(agent, configDir, log2) {
14882
14934
  if (!file.endsWith(".md")) continue;
14883
14935
  try {
14884
14936
  const raw = readFileSync18(join22(memoryDir, file), "utf-8");
14885
- const fileHash = createHash14("sha256").update(raw).digest("hex").slice(0, 16);
14937
+ const fileHash = createHash15("sha256").update(raw).digest("hex").slice(0, 16);
14886
14938
  currentHashes.set(file, fileHash);
14887
14939
  if (prevHashes.get(file) === fileHash) continue;
14888
14940
  const parsed = parseMemoryFile(raw, file.replace(/\.md$/, ""));
@@ -14920,14 +14972,14 @@ async function syncMemories(agent, configDir, log2) {
14920
14972
  }
14921
14973
  async function downloadMemories(agent, memoryDir, log2, { force }) {
14922
14974
  const localFiles = existsSync11(memoryDir) ? readdirSync6(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
14923
- const localListHash = createHash14("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
14975
+ const localListHash = createHash15("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
14924
14976
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
14925
14977
  const prevDownload = lastDownloadHash.get(agent.agent_id);
14926
14978
  try {
14927
14979
  const dbMemories = await api.post("/host/memories", {
14928
14980
  agent_id: agent.agent_id
14929
14981
  });
14930
- const responseHash = createHash14("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
14982
+ const responseHash = createHash15("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
14931
14983
  if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
14932
14984
  return true;
14933
14985
  }
@@ -14966,7 +15018,7 @@ ${mem.content}
14966
15018
  }
14967
15019
  if (written > 0 || overwritten > 0) {
14968
15020
  const updatedFiles = readdirSync6(memoryDir).filter((f) => f.endsWith(".md")).sort();
14969
- lastLocalFileHash.set(agent.agent_id, createHash14("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
15021
+ lastLocalFileHash.set(agent.agent_id, createHash15("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
14970
15022
  log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
14971
15023
  }
14972
15024
  }
@@ -15391,7 +15443,7 @@ function deployMcpAssets() {
15391
15443
  const fileHash = (p) => {
15392
15444
  try {
15393
15445
  if (!existsSync11(p)) return null;
15394
- return createHash14("sha256").update(readFileSync18(p)).digest("hex");
15446
+ return createHash15("sha256").update(readFileSync18(p)).digest("hex");
15395
15447
  } catch {
15396
15448
  return null;
15397
15449
  }