@integrity-labs/agt-cli 0.28.250 → 0.28.252

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
@@ -38,7 +38,7 @@ import {
38
38
  success,
39
39
  table,
40
40
  warn
41
- } from "../chunk-FQBAABKO.js";
41
+ } from "../chunk-U2VQQ2UK.js";
42
42
  import {
43
43
  CHANNEL_REGISTRY,
44
44
  DEFAULT_FRAMEWORK,
@@ -4826,7 +4826,7 @@ import { execFileSync, execSync } from "child_process";
4826
4826
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4827
4827
  import chalk18 from "chalk";
4828
4828
  import ora16 from "ora";
4829
- var cliVersion = true ? "0.28.250" : "dev";
4829
+ var cliVersion = true ? "0.28.252" : "dev";
4830
4830
  async function fetchLatestVersion() {
4831
4831
  const host2 = getHost();
4832
4832
  if (!host2) return null;
@@ -5840,7 +5840,7 @@ function handleError(err) {
5840
5840
  }
5841
5841
 
5842
5842
  // src/bin/agt.ts
5843
- var cliVersion2 = true ? "0.28.250" : "dev";
5843
+ var cliVersion2 = true ? "0.28.252" : "dev";
5844
5844
  var program = new Command();
5845
5845
  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");
5846
5846
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -5832,7 +5832,7 @@ function requireHost() {
5832
5832
  }
5833
5833
 
5834
5834
  // src/lib/api-client.ts
5835
- var agtCliVersion = true ? "0.28.250" : "dev";
5835
+ var agtCliVersion = true ? "0.28.252" : "dev";
5836
5836
  var lastConfigHash = null;
5837
5837
  function setConfigHash(hash) {
5838
5838
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8102,4 +8102,4 @@ export {
8102
8102
  managerInstallSystemUnitCommand,
8103
8103
  managerUninstallSystemUnitCommand
8104
8104
  };
8105
- //# sourceMappingURL=chunk-FQBAABKO.js.map
8105
+ //# sourceMappingURL=chunk-U2VQQ2UK.js.map
@@ -37,7 +37,7 @@ import {
37
37
  requireHost,
38
38
  safeWriteJsonAtomic,
39
39
  setConfigHash
40
- } from "../chunk-FQBAABKO.js";
40
+ } from "../chunk-U2VQQ2UK.js";
41
41
  import {
42
42
  getProjectDir as getProjectDir2,
43
43
  getReadyTasks,
@@ -128,7 +128,7 @@ import {
128
128
  } from "../chunk-XWVM4KPK.js";
129
129
 
130
130
  // src/lib/manager-worker.ts
131
- import { createHash as createHash10 } from "crypto";
131
+ import { createHash as createHash11 } from "crypto";
132
132
  import { readFileSync as readFileSync14, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, existsSync as existsSync8, rmSync as rmSync4, readdirSync as readdirSync5, statSync as statSync4, copyFileSync } from "fs";
133
133
  import { execFileSync as syncExecFile } from "child_process";
134
134
  import { join as join16, dirname as dirname5 } from "path";
@@ -318,6 +318,49 @@ function decideSenderPolicyRestart(input) {
318
318
  return { restart: true, firstPoll: false, changed: true };
319
319
  }
320
320
 
321
+ // src/lib/sender-policy-normalize.ts
322
+ import { createHash as createHash3 } from "crypto";
323
+
324
+ // src/lib/canonical-json.ts
325
+ function canonicalJson(value) {
326
+ return JSON.stringify(normalize(value));
327
+ }
328
+ function normalize(value) {
329
+ if (value === null || typeof value !== "object") return value;
330
+ if (Array.isArray(value)) return value.map(normalize);
331
+ const sorted = {};
332
+ const keys = Object.keys(value).sort();
333
+ for (const k of keys) {
334
+ sorted[k] = normalize(value[k]);
335
+ }
336
+ return sorted;
337
+ }
338
+
339
+ // src/lib/sender-policy-normalize.ts
340
+ var PRINCIPAL_ID_LIST_KEYS = [
341
+ "slack_user_ids",
342
+ "telegram_chat_ids",
343
+ "teams_aad_object_ids"
344
+ ];
345
+ function normalizeSenderPolicyForHash(policy) {
346
+ if (policy === null || typeof policy !== "object") return policy;
347
+ const p = policy;
348
+ const tp = p.team_principals;
349
+ if (tp === null || typeof tp !== "object") return policy;
350
+ const src = tp;
351
+ const normalizedTeamPrincipals = { ...src };
352
+ for (const key of PRINCIPAL_ID_LIST_KEYS) {
353
+ const list = src[key];
354
+ if (Array.isArray(list)) {
355
+ normalizedTeamPrincipals[key] = [...list].sort();
356
+ }
357
+ }
358
+ return { ...p, team_principals: normalizedTeamPrincipals };
359
+ }
360
+ function computeSenderPolicyRestartHash(policy) {
361
+ return createHash3("sha256").update(canonicalJson({ senderPolicy: normalizeSenderPolicyForHash(policy) })).digest("hex");
362
+ }
363
+
321
364
  // src/lib/msteams-behaviour-restart.ts
322
365
  function extractMsTeamsBehaviourSubset(config2) {
323
366
  const adaptiveCardsEnabled = config2?.["adaptive_cards_enabled"] === true;
@@ -1405,7 +1448,7 @@ function isDirectChatMessageExpired(createdAt, nowMs, maxAgeMs) {
1405
1448
  }
1406
1449
 
1407
1450
  // ../../packages/core/dist/host-config/capture.js
1408
- import { createHash as createHash3 } from "crypto";
1451
+ import { createHash as createHash4 } from "crypto";
1409
1452
  var NON_SECRET_ENV_GATES = [
1410
1453
  "AGT_MEMORY_EXTRACTION_ENABLED",
1411
1454
  "AGT_CHANNEL_REPLAY_ENABLED",
@@ -2358,6 +2401,114 @@ function readRecentTurns(dir, nowMs) {
2358
2401
  return turns;
2359
2402
  }
2360
2403
 
2404
+ // src/lib/routine-candidate-extractor.ts
2405
+ var VALID_CADENCE_GUESSES = /* @__PURE__ */ new Set(["daily", "weekdays", "weekly", "unknown"]);
2406
+ var MAX_ASK_CHARS = 400;
2407
+ var MAX_INPUT_CHARS = 6e3;
2408
+ function buildUserAsksInput(turns) {
2409
+ const lines = [];
2410
+ let total = 0;
2411
+ for (const turn of turns) {
2412
+ if (turn.role !== "user") continue;
2413
+ const body = turn.text.length > MAX_ASK_CHARS ? `${turn.text.slice(0, MAX_ASK_CHARS)}\u2026` : turn.text;
2414
+ const line = `User: ${body}`;
2415
+ if (total + line.length > MAX_INPUT_CHARS) break;
2416
+ lines.push(line);
2417
+ total += line.length;
2418
+ }
2419
+ return lines.join("\n");
2420
+ }
2421
+ function buildRoutinePrompt(channel, userAsks) {
2422
+ return `You are looking for a DURABLE RECURRING ASK in the user's messages from one completed ${channel} conversation with an AI agent. A routine candidate is something the user asks for repeatedly or explicitly wants on a schedule ("every morning", "each Friday", "again" for the third time) - not a one-off task.
2423
+
2424
+ User messages (agent replies deliberately omitted):
2425
+ """
2426
+ ${userAsks}
2427
+ """
2428
+
2429
+ Extract 0-2 routine candidates. For each:
2430
+ - description: the recurring ask, self-contained and generic (max 200 chars). No secrets, no personal data beyond what is needed to name the task.
2431
+ - cadence_guess: "daily", "weekdays", "weekly", or "unknown" if the messages imply repetition without a clear cadence
2432
+ - evidence_count: how many of the user messages above support this ask (integer >= 1)
2433
+ - confidence: 0.0-1.0 - how sure you are this is a genuine recurring responsibility
2434
+
2435
+ Most conversations contain NO routine candidate - return an empty array unless the recurrence signal is clear. Do NOT invent candidates.
2436
+
2437
+ Respond with ONLY a JSON array, no other text:
2438
+ [{"description":"...","cadence_guess":"daily","evidence_count":2,"confidence":0.7}]`;
2439
+ }
2440
+ function parseRoutineCandidates(raw) {
2441
+ const match = raw.match(/\[[\s\S]*\]/);
2442
+ if (!match) return null;
2443
+ let arr;
2444
+ try {
2445
+ arr = JSON.parse(match[0]);
2446
+ } catch {
2447
+ return null;
2448
+ }
2449
+ if (!Array.isArray(arr)) return null;
2450
+ const out = [];
2451
+ for (const entry of arr) {
2452
+ if (!entry || typeof entry !== "object") continue;
2453
+ const c = entry;
2454
+ const description = typeof c.description === "string" ? c.description.trim() : "";
2455
+ if (!description) continue;
2456
+ const confidence = typeof c.confidence === "number" && Number.isFinite(c.confidence) ? Math.max(0, Math.min(1, c.confidence)) : 0;
2457
+ if (confidence === 0) continue;
2458
+ const cadence = typeof c.cadence_guess === "string" && VALID_CADENCE_GUESSES.has(c.cadence_guess) ? c.cadence_guess : "unknown";
2459
+ const evidenceRaw = typeof c.evidence_count === "number" && Number.isFinite(c.evidence_count) ? Math.floor(c.evidence_count) : 1;
2460
+ out.push({
2461
+ // Bounded parse only - the FINAL 200-char truncation happens after
2462
+ // scrubbing (maybeEmitRoutineCandidates), because slicing first can
2463
+ // split a secret across the cut so the scrub regex no longer matches
2464
+ // and a fragment leaks onto the wire.
2465
+ description: description.slice(0, 500),
2466
+ cadence_guess: cadence,
2467
+ evidence_count: Math.max(1, Math.min(50, evidenceRaw)),
2468
+ confidence
2469
+ });
2470
+ }
2471
+ return out;
2472
+ }
2473
+ async function maybeEmitRoutineCandidates(args) {
2474
+ const { api: api2, backend, codeName, agentId, conversationId, channel, turns, log: log2 } = args;
2475
+ try {
2476
+ const userAsks = buildUserAsksInput(turns);
2477
+ if (!userAsks.trim()) return;
2478
+ let candidates;
2479
+ try {
2480
+ const out = await backend.run(buildRoutinePrompt(channel, userAsks));
2481
+ candidates = parseRoutineCandidates(out);
2482
+ } catch (err) {
2483
+ log2(`[routine-extract] ${codeName}: extraction failed: ${err.message}`);
2484
+ args.onModelCallError?.(err);
2485
+ return;
2486
+ }
2487
+ if (!candidates || candidates.length === 0) return;
2488
+ const scrubbed = candidates.map((c) => ({
2489
+ ...c,
2490
+ description: scrubSensitive(c.description).slice(0, 200)
2491
+ }));
2492
+ try {
2493
+ const res = await api2.post(
2494
+ "/host/routines/candidates",
2495
+ {
2496
+ agent_id: agentId,
2497
+ conversation_id: conversationId,
2498
+ candidates: scrubbed
2499
+ }
2500
+ );
2501
+ log2(
2502
+ `[routine-extract] ${codeName}: ${conversationId.slice(0, 8)} \u2192 ${scrubbed.length} candidate(s)${res?.discarded ? " (discarded: feature off)" : ""}`
2503
+ );
2504
+ } catch (err) {
2505
+ log2(`[routine-extract] ${codeName}: report failed: ${err.message}`);
2506
+ }
2507
+ } catch (err) {
2508
+ log2(`[routine-extract] ${codeName}: unexpected error: ${err.message}`);
2509
+ }
2510
+ }
2511
+
2361
2512
  // src/lib/memory-extractor.ts
2362
2513
  var MIN_CHECK_INTERVAL_MS5 = 10 * 6e4;
2363
2514
  var WINDOW_PAD_MS2 = 5 * 6e4;
@@ -2503,6 +2654,17 @@ async function maybeExtractMemories(args) {
2503
2654
  } catch (err) {
2504
2655
  log2(`[memory-extract] ${codeName}: report failed: ${err.message}`);
2505
2656
  }
2657
+ await maybeEmitRoutineCandidates({
2658
+ api: api2,
2659
+ backend,
2660
+ codeName,
2661
+ agentId,
2662
+ conversationId: conv.conversation_id,
2663
+ channel: conv.channel,
2664
+ turns,
2665
+ log: log2,
2666
+ onModelCallError: args.onModelCallError
2667
+ });
2506
2668
  }
2507
2669
  }
2508
2670
  async function reportSkip2(api2, agentId, conversationId, log2, codeName) {
@@ -2858,26 +3020,11 @@ function parseExpiresAt(raw) {
2858
3020
  return null;
2859
3021
  }
2860
3022
 
2861
- // src/lib/canonical-json.ts
2862
- function canonicalJson(value) {
2863
- return JSON.stringify(normalize(value));
2864
- }
2865
- function normalize(value) {
2866
- if (value === null || typeof value !== "object") return value;
2867
- if (Array.isArray(value)) return value.map(normalize);
2868
- const sorted = {};
2869
- const keys = Object.keys(value).sort();
2870
- for (const k of keys) {
2871
- sorted[k] = normalize(value[k]);
2872
- }
2873
- return sorted;
2874
- }
2875
-
2876
3023
  // src/lib/channel-config-hash.ts
2877
- import { createHash as createHash4 } from "crypto";
3024
+ import { createHash as createHash5 } from "crypto";
2878
3025
  var CHANNEL_WRITE_VERSION = 9;
2879
3026
  function computeChannelConfigHash(input) {
2880
- return createHash4("sha256").update(
3027
+ return createHash5("sha256").update(
2881
3028
  canonicalJson({
2882
3029
  writeVersion: CHANNEL_WRITE_VERSION,
2883
3030
  cliVersion: input.cliVersion,
@@ -2885,7 +3032,9 @@ function computeChannelConfigHash(input) {
2885
3032
  team: input.team,
2886
3033
  peers: input.peers,
2887
3034
  sessionMode: input.sessionMode ?? null,
2888
- senderPolicy: input.senderPolicy
3035
+ // ENG-7435: value-blind on the team_principals id SETS so a reorder of
3036
+ // the same principals can't oscillate this hash into a false rewrite.
3037
+ senderPolicy: normalizeSenderPolicyForHash(input.senderPolicy)
2889
3038
  })
2890
3039
  ).digest("hex");
2891
3040
  }
@@ -3302,7 +3451,7 @@ function planGlobalSkillSync(globalSkills, prevIds, hashOf, knownHash) {
3302
3451
  }
3303
3452
 
3304
3453
  // src/lib/manager/runtime.ts
3305
- import { createHash as createHash5 } from "crypto";
3454
+ import { createHash as createHash6 } from "crypto";
3306
3455
  import { readFileSync as readFileSync11, appendFileSync, mkdirSync as mkdirSync4, chmodSync, existsSync as existsSync4 } from "fs";
3307
3456
  import { join as join11, dirname as dirname4 } from "path";
3308
3457
  import { homedir as homedir5 } from "os";
@@ -3351,7 +3500,7 @@ function log(msg) {
3351
3500
  }
3352
3501
  }
3353
3502
  function sha256(content) {
3354
- return createHash5("sha256").update(content, "utf8").digest("hex");
3503
+ return createHash6("sha256").update(content, "utf8").digest("hex");
3355
3504
  }
3356
3505
  function hashFile(filePath) {
3357
3506
  try {
@@ -3815,7 +3964,7 @@ function formatBoardForPrompt(items, template) {
3815
3964
  }
3816
3965
 
3817
3966
  // src/lib/manager/kanban/notify.ts
3818
- import { createHash as createHash6 } from "crypto";
3967
+ import { createHash as createHash7 } from "crypto";
3819
3968
  async function enqueueKanbanNotice(opts) {
3820
3969
  try {
3821
3970
  const res = await api.post(
@@ -3830,7 +3979,7 @@ async function enqueueKanbanNotice(opts) {
3830
3979
  return res.ok === true;
3831
3980
  } catch (err) {
3832
3981
  const errText = err instanceof Error ? err.message : String(err);
3833
- const errId = createHash6("sha256").update(errText).digest("hex").slice(0, 12);
3982
+ const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
3834
3983
  log(`[kanban] notice enqueue failed for agent_id=${opts.agentId} error_id=${errId}`);
3835
3984
  return false;
3836
3985
  }
@@ -4197,7 +4346,7 @@ function deriveScheduledTaskNotify(task) {
4197
4346
  }
4198
4347
 
4199
4348
  // src/lib/manager/scheduler/runs.ts
4200
- import { createHash as createHash7 } from "crypto";
4349
+ import { createHash as createHash8 } from "crypto";
4201
4350
  async function startRun(opts) {
4202
4351
  try {
4203
4352
  const res = await api.post(
@@ -4207,7 +4356,7 @@ async function startRun(opts) {
4207
4356
  return { run_id: res.run_id ?? null, kanban_item_id: res.kanban_item_id ?? null };
4208
4357
  } catch (err) {
4209
4358
  const errText = err instanceof Error ? err.message : String(err);
4210
- const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
4359
+ const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
4211
4360
  log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
4212
4361
  return { run_id: null, kanban_item_id: null };
4213
4362
  }
@@ -4224,7 +4373,7 @@ async function finishRun(runId, outcome, options = {}) {
4224
4373
  });
4225
4374
  } catch (err) {
4226
4375
  const errText = err instanceof Error ? err.message : String(err);
4227
- const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
4376
+ const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
4228
4377
  log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
4229
4378
  }
4230
4379
  }
@@ -4241,7 +4390,7 @@ async function fetchPriorScheduledRuns(agentId, taskId) {
4241
4390
  return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
4242
4391
  } catch (err) {
4243
4392
  const errText = err instanceof Error ? err.message : String(err);
4244
- const errId = createHash7("sha256").update(errText).digest("hex").slice(0, 12);
4393
+ const errId = createHash8("sha256").update(errText).digest("hex").slice(0, 12);
4245
4394
  log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
4246
4395
  return [];
4247
4396
  }
@@ -4290,7 +4439,7 @@ function closeScheduledRunsForCode(codeName, outcome, reason) {
4290
4439
  }
4291
4440
 
4292
4441
  // src/lib/manager/scheduler/kanban-route.ts
4293
- import { createHash as createHash8 } from "crypto";
4442
+ import { createHash as createHash9 } from "crypto";
4294
4443
 
4295
4444
  // src/lib/delivery-schedule-link.ts
4296
4445
  function envSuffixFor2(codeName) {
@@ -4722,24 +4871,24 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
4722
4871
  const assertion = parseDeliverAssertion(rawOutput);
4723
4872
  if (!assertion.deliver) {
4724
4873
  const trimmed = (rawOutput ?? "").trim();
4725
- const outputHash = trimmed.length === 0 ? "empty" : createHash8("sha256").update(trimmed).digest("hex").slice(0, 12);
4874
+ const outputHash = trimmed.length === 0 ? "empty" : createHash9("sha256").update(trimmed).digest("hex").slice(0, 12);
4726
4875
  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}`);
4727
4876
  if (delivery?.mode === "announce" && delivery.to) {
4728
4877
  await reportDeliveryStatus(agentId, delivery.taskId, { status: "skipped", error_code: "SUPPRESSED_BY_POLICY" });
4729
4878
  }
4730
4879
  return { ok: true };
4731
4880
  }
4732
- const reasonHash = createHash8("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
4881
+ const reasonHash = createHash9("sha256").update(assertion.reason ?? "").digest("hex").slice(0, 12);
4733
4882
  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})`);
4734
4883
  rawOutput = assertion.deliverable;
4735
4884
  }
4736
4885
  const classification = classifyOutput(rawOutput);
4737
4886
  if (classification.action === "suppress") {
4738
4887
  const trimmed = (rawOutput ?? "").trim();
4739
- const outputHash = trimmed.length === 0 ? "empty" : createHash8("sha256").update(trimmed).digest("hex").slice(0, 12);
4888
+ const outputHash = trimmed.length === 0 ? "empty" : createHash9("sha256").update(trimmed).digest("hex").slice(0, 12);
4740
4889
  log(`[claude-scheduler] Suppressing delivery for '${codeName}' (template=${templateId}, task=${delivery?.taskId ?? "n/a"}) \u2014 output_len=${trimmed.length} output_hash=${outputHash}`);
4741
4890
  if (classification.suppressedNotes) {
4742
- const notesHash = createHash8("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
4891
+ const notesHash = createHash9("sha256").update(classification.suppressedNotes).digest("hex").slice(0, 12);
4743
4892
  log(`[claude-scheduler] Suppressed notes for '${codeName}' (task=${delivery?.taskId ?? "n/a"}) \u2014 notes_len=${classification.suppressedNotes.length} notes_hash=${notesHash}`);
4744
4893
  }
4745
4894
  if (delivery?.mode === "announce" && delivery.to) {
@@ -4805,7 +4954,7 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
4805
4954
  }
4806
4955
 
4807
4956
  // src/lib/manager/scheduler/execution.ts
4808
- import { createHash as createHash9 } from "crypto";
4957
+ import { createHash as createHash10 } from "crypto";
4809
4958
  import { homedir as homedir7 } from "os";
4810
4959
  import { join as join14 } from "path";
4811
4960
  function claudePidFilePath() {
@@ -4829,10 +4978,10 @@ function unregisterClaudeSpawn(pid) {
4829
4978
  }
4830
4979
  async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData) {
4831
4980
  const codeName = agent.code_name;
4832
- const stableTasksHash = createHash9("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
4833
- const boardHash = boardItems.length > 0 ? createHash9("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";
4981
+ const stableTasksHash = createHash10("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
4982
+ 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";
4834
4983
  const resolvedModels = resolveModelChain(refreshData);
4835
- const modelsHash = createHash9("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
4984
+ const modelsHash = createHash10("sha256").update(JSON.stringify(resolvedModels)).digest("hex").slice(0, 16);
4836
4985
  const combinedHash = `${stableTasksHash}:${boardHash}:${modelsHash}`;
4837
4986
  const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
4838
4987
  if (combinedHash !== prevHash) {
@@ -6206,7 +6355,7 @@ var runningChannelSecretHashes = /* @__PURE__ */ new Map();
6206
6355
  function projectMcpHash(_codeName, projectDir) {
6207
6356
  try {
6208
6357
  const raw = readFileSync14(join16(projectDir, ".mcp.json"), "utf-8");
6209
- return createHash10("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
6358
+ return createHash11("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
6210
6359
  } catch {
6211
6360
  return null;
6212
6361
  }
@@ -6520,7 +6669,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6520
6669
  var lastVersionCheckAt = 0;
6521
6670
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6522
6671
  var lastResponsivenessProbeAt = 0;
6523
- var agtCliVersion = true ? "0.28.250" : "dev";
6672
+ var agtCliVersion = true ? "0.28.252" : "dev";
6524
6673
  function resolveBrewPath(execFileSync2) {
6525
6674
  try {
6526
6675
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7498,7 +7647,7 @@ async function pollCycle() {
7498
7647
  claudeAuth = await detectClaudeAuth();
7499
7648
  } catch (err) {
7500
7649
  const errText = err instanceof Error ? err.message : String(err);
7501
- const errId = createHash10("sha256").update(errText).digest("hex").slice(0, 12);
7650
+ const errId = createHash11("sha256").update(errText).digest("hex").slice(0, 12);
7502
7651
  log(`Claude auth detection failed (error_id=${errId})`);
7503
7652
  }
7504
7653
  const hostHasClaudeCode = state6.agents.some(
@@ -8825,7 +8974,7 @@ async function processAgent(agent, agentStates) {
8825
8974
  if (channelConfigConverged) {
8826
8975
  const hasSenderPolicyChannel = currentChannelIds.has("slack") || currentChannelIds.has("msteams");
8827
8976
  const senderPolicyForRestartHash = refreshData.sender_policy ?? null;
8828
- const senderPolicyHash = createHash10("sha256").update(canonicalJson({ senderPolicy: senderPolicyForRestartHash })).digest("hex");
8977
+ const senderPolicyHash = computeSenderPolicyRestartHash(senderPolicyForRestartHash);
8829
8978
  const prevSenderPolicyHash = agentState.knownSenderPolicyHashes.get(agent.agent_id);
8830
8979
  const senderPolicyDecision = hasSenderPolicyChannel ? decideSenderPolicyRestart({
8831
8980
  previousHash: prevSenderPolicyHash,
@@ -8867,7 +9016,7 @@ async function processAgent(agent, agentStates) {
8867
9016
  const behaviourSubset = extractMsTeamsBehaviourSubset(
8868
9017
  msteamsEntry?.config
8869
9018
  );
8870
- const behaviourHash = createHash10("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
9019
+ const behaviourHash = createHash11("sha256").update(canonicalJson(behaviourSubset)).digest("hex");
8871
9020
  const prevBehaviourHash = agentState.knownMsTeamsBehaviourHashes.get(agent.agent_id);
8872
9021
  const behaviourDecision = decideSenderPolicyRestart({
8873
9022
  previousHash: prevBehaviourHash,
@@ -8914,7 +9063,7 @@ async function processAgent(agent, agentStates) {
8914
9063
  const slackBehaviourSubset = extractSlackBehaviourSubset(
8915
9064
  slackEntry?.config
8916
9065
  );
8917
- const slackBehaviourHash = createHash10("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
9066
+ const slackBehaviourHash = createHash11("sha256").update(canonicalJson(slackBehaviourSubset)).digest("hex");
8918
9067
  const prevSlackBehaviourHash = agentState.knownSlackBehaviourHashes.get(agent.agent_id);
8919
9068
  const slackBehaviourDecision = decideSenderPolicyRestart({
8920
9069
  previousHash: prevSlackBehaviourHash,
@@ -9213,10 +9362,10 @@ async function processAgent(agent, agentStates) {
9213
9362
  desiredEntries.push({ serverId, url, headers: mcpHeaders, name: tk.toolkit_name });
9214
9363
  }
9215
9364
  const hashBasis = desiredEntries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => {
9216
- const headersHash = createHash10("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
9365
+ const headersHash = createHash11("sha256").update(canonicalJson(e.headers ?? {})).digest("hex").slice(0, 16);
9217
9366
  return `${e.serverId}|${e.url}|${headersHash}`;
9218
9367
  }).join("\n");
9219
- const mcpHash = createHash10("sha256").update(hashBasis).digest("hex").slice(0, 16);
9368
+ const mcpHash = createHash11("sha256").update(hashBasis).digest("hex").slice(0, 16);
9220
9369
  const prevMcpHash = agentState.knownManagedMcpHashes.get(agent.agent_id);
9221
9370
  const structureHash = managedMcpStructureHash(desiredEntries);
9222
9371
  const prevStructureHash = agentState.knownManagedMcpStructure.get(agent.agent_id);
@@ -9231,7 +9380,7 @@ async function processAgent(agent, agentStates) {
9231
9380
  if (mcpHash !== prevMcpHash) {
9232
9381
  for (const e of desiredEntries) {
9233
9382
  frameworkAdapter.writeMcpServer(agent.code_name, e.serverId, { url: e.url, headers: e.headers });
9234
- const urlHash = createHash10("sha256").update(e.url).digest("hex").slice(0, 12);
9383
+ const urlHash = createHash11("sha256").update(e.url).digest("hex").slice(0, 12);
9235
9384
  log(`[managed-toolkit] ${agent.code_name}: wrote '${e.name}' (serverId=${e.serverId}, url_hash=${urlHash})`);
9236
9385
  }
9237
9386
  if (frameworkAdapter.removeMcpServer && frameworkAdapter.getMcpPath) {
@@ -9333,7 +9482,7 @@ async function processAgent(agent, agentStates) {
9333
9482
  if (frameworkAdapter.installSkillFiles) {
9334
9483
  const currentIntegrationSkillIds = /* @__PURE__ */ new Set();
9335
9484
  const installedIntegrationSkills = [];
9336
- const { createHash: createHash11 } = await import("crypto");
9485
+ const { createHash: createHash12 } = await import("crypto");
9337
9486
  const refreshAny = refreshData;
9338
9487
  const contexts = refreshAny.integration_contexts ?? refreshAny.plugin_contexts ?? [];
9339
9488
  const contextBySlug = /* @__PURE__ */ new Map();
@@ -9362,7 +9511,7 @@ async function processAgent(agent, agentStates) {
9362
9511
  )
9363
9512
  }));
9364
9513
  const bundle = buildIntegrationBundle(renderedScopes);
9365
- const contentHash = createHash11("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
9514
+ const contentHash = createHash12("sha256").update(bundleFingerprint(bundle.files)).digest("hex").slice(0, 12);
9366
9515
  const hashKey = `plugin-skill:${agent.agent_id}:${integrationSkillId}`;
9367
9516
  if (agentState.knownSkillHashes.get(hashKey) === contentHash) continue;
9368
9517
  frameworkAdapter.installSkillFiles(agent.code_name, integrationSkillId, bundle.files);
@@ -9419,7 +9568,7 @@ async function processAgent(agent, agentStates) {
9419
9568
  const plan = planGlobalSkillSync(
9420
9569
  [...refreshAny.global_skills ?? [], ...refreshAny.shared_skills ?? []],
9421
9570
  agentState.knownGlobalSkillIds.get(agent.agent_id) ?? /* @__PURE__ */ new Set(),
9422
- (content) => createHash11("sha256").update(content).digest("hex").slice(0, 12),
9571
+ (content) => createHash12("sha256").update(content).digest("hex").slice(0, 12),
9423
9572
  (skillId) => agentState.knownSkillHashes.get(`global-skill:${agent.agent_id}:${skillId}`)
9424
9573
  );
9425
9574
  for (const { skillId, content, hash } of plan.installs) {
@@ -9462,7 +9611,7 @@ async function processAgent(agent, agentStates) {
9462
9611
  const slug = hook.integration_slug ?? hook.plugin_slug;
9463
9612
  if (!slug) continue;
9464
9613
  try {
9465
- const scriptHash = createHash11("sha256").update(hook.script).digest("hex").slice(0, 12);
9614
+ const scriptHash = createHash12("sha256").update(hook.script).digest("hex").slice(0, 12);
9466
9615
  const hookKey = `${agent.agent_id}:${frameworkAdapter.id}:plugin-hook:${slug}:on_install`;
9467
9616
  if (agentState.knownSkillHashes.get(hookKey) === scriptHash) continue;
9468
9617
  const result = await frameworkAdapter.executePluginHook({
@@ -9477,9 +9626,9 @@ async function processAgent(agent, agentStates) {
9477
9626
  } else if (result.timedOut) {
9478
9627
  log(`Integration hook on_install '${slug}' TIMED OUT for '${agent.code_name}' after ${result.durationMs}ms`);
9479
9628
  } else {
9480
- const stderrHash = createHash11("sha256").update(result.stderr).digest("hex").slice(0, 12);
9629
+ const stderrHash = createHash12("sha256").update(result.stderr).digest("hex").slice(0, 12);
9481
9630
  const missingCmd = result.exitCode === 127 ? extractCommandNotFound(result.stderr) : null;
9482
- const missingCmdHash = missingCmd ? createHash11("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
9631
+ const missingCmdHash = missingCmd ? createHash12("sha256").update(missingCmd).digest("hex").slice(0, 8) : null;
9483
9632
  log(
9484
9633
  `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}]`
9485
9634
  );
@@ -10107,7 +10256,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
10107
10256
  const ctx = getLastFailureContext(codeName);
10108
10257
  const recovery = prepareForRespawn(codeName);
10109
10258
  const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
10110
- ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash10("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
10259
+ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash11("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
10111
10260
  const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
10112
10261
  const recoverySummary = recovery ? `; recovery=${recovery}` : "";
10113
10262
  log(
@@ -10121,7 +10270,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash10("sha256")
10121
10270
  );
10122
10271
  getHostId().then((hostId) => {
10123
10272
  if (!hostId) return;
10124
- const paneTailHash = zombie.paneTail ? `sha256:${createHash10("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
10273
+ const paneTailHash = zombie.paneTail ? `sha256:${createHash11("sha256").update(zombie.paneTail).digest("hex").slice(0, 12)}` : null;
10125
10274
  return api.post("/host/events", {
10126
10275
  host_id: hostId,
10127
10276
  agent_code_name: codeName,
@@ -10257,7 +10406,7 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash10("sha256")
10257
10406
  if (!claudeAuthTupleBySession.has(codeName)) {
10258
10407
  claudeAuthTupleBySession.set(codeName, currentAuthTuple);
10259
10408
  }
10260
- const stableTasksHash = createHash10("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
10409
+ const stableTasksHash = createHash11("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
10261
10410
  const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
10262
10411
  if (stableTasksHash !== prevHash) {
10263
10412
  const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
@@ -11178,7 +11327,7 @@ async function syncMemories(agent, configDir, log2) {
11178
11327
  if (!file.endsWith(".md")) continue;
11179
11328
  try {
11180
11329
  const raw = readFileSync14(join16(memoryDir, file), "utf-8");
11181
- const fileHash = createHash10("sha256").update(raw).digest("hex").slice(0, 16);
11330
+ const fileHash = createHash11("sha256").update(raw).digest("hex").slice(0, 16);
11182
11331
  currentHashes.set(file, fileHash);
11183
11332
  if (prevHashes.get(file) === fileHash) continue;
11184
11333
  const parsed = parseMemoryFile(raw, file.replace(/\.md$/, ""));
@@ -11216,14 +11365,14 @@ async function syncMemories(agent, configDir, log2) {
11216
11365
  }
11217
11366
  async function downloadMemories(agent, memoryDir, log2, { force }) {
11218
11367
  const localFiles = existsSync8(memoryDir) ? readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
11219
- const localListHash = createHash10("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
11368
+ const localListHash = createHash11("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
11220
11369
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
11221
11370
  const prevDownload = lastDownloadHash.get(agent.agent_id);
11222
11371
  try {
11223
11372
  const dbMemories = await api.post("/host/memories", {
11224
11373
  agent_id: agent.agent_id
11225
11374
  });
11226
- const responseHash = createHash10("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
11375
+ const responseHash = createHash11("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
11227
11376
  if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
11228
11377
  return true;
11229
11378
  }
@@ -11262,7 +11411,7 @@ ${mem.content}
11262
11411
  }
11263
11412
  if (written > 0 || overwritten > 0) {
11264
11413
  const updatedFiles = readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort();
11265
- lastLocalFileHash.set(agent.agent_id, createHash10("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
11414
+ lastLocalFileHash.set(agent.agent_id, createHash11("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
11266
11415
  log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
11267
11416
  }
11268
11417
  }
@@ -11675,7 +11824,7 @@ function deployMcpAssets() {
11675
11824
  const fileHash = (p) => {
11676
11825
  try {
11677
11826
  if (!existsSync8(p)) return null;
11678
- return createHash10("sha256").update(readFileSync14(p)).digest("hex");
11827
+ return createHash11("sha256").update(readFileSync14(p)).digest("hex");
11679
11828
  } catch {
11680
11829
  return null;
11681
11830
  }