@integrity-labs/agt-cli 0.28.906 → 0.28.908

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.
@@ -63,7 +63,7 @@ import {
63
63
  safeWriteJsonAtomic,
64
64
  setConfigHash,
65
65
  tripClass
66
- } from "../chunk-PNIRMJTW.js";
66
+ } from "../chunk-KJ7A7K2S.js";
67
67
  import {
68
68
  getProjectDir as getProjectDir2,
69
69
  getReadyTasks,
@@ -238,7 +238,7 @@ import {
238
238
 
239
239
  // src/lib/manager-worker.ts
240
240
  import { createHash as createHash20 } from "crypto";
241
- import { readFileSync as readFileSync32, writeFileSync as writeFileSync18, mkdirSync as mkdirSync15, existsSync as existsSync19, rmSync as rmSync8, readdirSync as readdirSync12, statSync as statSync11, unlinkSync as unlinkSync6, renameSync as renameSync11, utimesSync as utimesSync4 } from "fs";
241
+ import { readFileSync as readFileSync33, writeFileSync as writeFileSync18, mkdirSync as mkdirSync15, existsSync as existsSync19, rmSync as rmSync8, readdirSync as readdirSync12, statSync as statSync12, unlinkSync as unlinkSync6, renameSync as renameSync11, utimesSync as utimesSync4 } from "fs";
242
242
 
243
243
  // src/lib/atomic-file-replace.ts
244
244
  import { copyFileSync, renameSync, unlinkSync } from "fs";
@@ -264,8 +264,8 @@ function defaultUnique() {
264
264
 
265
265
  // src/lib/manager-worker.ts
266
266
  import { execFileSync as syncExecFile } from "child_process";
267
- import { join as join41, dirname as dirname11, delimiter as pathDelimiter } from "path";
268
- import { homedir as homedir17 } from "os";
267
+ import { join as join42, dirname as dirname11, delimiter as pathDelimiter } from "path";
268
+ import { homedir as homedir18 } from "os";
269
269
  import { fileURLToPath as fileURLToPath2 } from "url";
270
270
 
271
271
  // ../../packages/core/dist/provisioning/channel-policy-env.js
@@ -1858,11 +1858,11 @@ function isPathInsideDir(candidate, dir) {
1858
1858
  }
1859
1859
  function findMissingMcpBundles(mcpConfigPath, deps = {}) {
1860
1860
  const existsSync20 = deps.existsSync ?? nodeExistsSync;
1861
- const readFileSync33 = deps.readFileSync ?? nodeReadFileSync;
1861
+ const readFileSync34 = deps.readFileSync ?? nodeReadFileSync;
1862
1862
  const mcpDir = deps.mcpDir ?? getSharedMcpDir();
1863
1863
  let parsed;
1864
1864
  try {
1865
- parsed = JSON.parse(readFileSync33(mcpConfigPath, "utf-8"));
1865
+ parsed = JSON.parse(readFileSync34(mcpConfigPath, "utf-8"));
1866
1866
  } catch {
1867
1867
  return [];
1868
1868
  }
@@ -6359,6 +6359,86 @@ function pruneStuckStreaksToAgents(maps, activeAgentIds) {
6359
6359
  return dropped;
6360
6360
  }
6361
6361
 
6362
+ // src/lib/claude-device-state.ts
6363
+ import { readFileSync as readFileSync24, statSync as statSync8 } from "fs";
6364
+ import { homedir as homedir13 } from "os";
6365
+ import { join as join30 } from "path";
6366
+ function claudeDeviceStatePath(env = process.env) {
6367
+ return join30(env.HOME?.trim() || homedir13(), ".claude.json");
6368
+ }
6369
+ function checkClaudeDeviceState(path = claudeDeviceStatePath()) {
6370
+ try {
6371
+ if (!statSync8(path).isFile()) return { usable: false, reason: "not-a-file" };
6372
+ } catch (err) {
6373
+ return {
6374
+ usable: false,
6375
+ reason: err?.code === "ENOENT" ? "missing" : "unreadable"
6376
+ };
6377
+ }
6378
+ let raw;
6379
+ try {
6380
+ raw = readFileSync24(path, "utf-8");
6381
+ } catch {
6382
+ return { usable: false, reason: "unreadable" };
6383
+ }
6384
+ let parsed;
6385
+ try {
6386
+ parsed = JSON.parse(raw);
6387
+ } catch {
6388
+ return { usable: false, reason: "unparseable" };
6389
+ }
6390
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
6391
+ return { usable: false, reason: "not-an-object" };
6392
+ }
6393
+ if (Object.keys(parsed).length === 0) return { usable: false, reason: "empty-object" };
6394
+ return { usable: true };
6395
+ }
6396
+ var DeviceStateRotationGate = class {
6397
+ constructor(check = () => checkClaudeDeviceState()) {
6398
+ this.check = check;
6399
+ }
6400
+ held = /* @__PURE__ */ new Map();
6401
+ /**
6402
+ * Ask before tearing `codeName`'s session down for a planned rotation.
6403
+ * Returns `ready: true` when the respawn can start; otherwise the rotation must
6404
+ * be skipped this tick. `firstHold` is true only on the tick a hold begins for
6405
+ * this agent, so the caller logs once per episode rather than every poll.
6406
+ */
6407
+ mayRotate(codeName, nowMs) {
6408
+ const verdict = this.check();
6409
+ if (verdict.usable) {
6410
+ this.held.clear();
6411
+ return { ready: true };
6412
+ }
6413
+ const firstHold = !this.held.has(codeName);
6414
+ if (firstHold) this.held.set(codeName, nowMs);
6415
+ return { ready: false, reason: verdict.reason, firstHold };
6416
+ }
6417
+ /**
6418
+ * The value for the heartbeat. Re-checks the file while anything is held, so
6419
+ * the alert closes on the next heartbeat after the operator pairs the host,
6420
+ * not only when some agent's rollover next asks. Reads nothing when nothing is
6421
+ * held, so a healthy host pays no file read per heartbeat.
6422
+ */
6423
+ heartbeatField() {
6424
+ if (this.held.size === 0) return null;
6425
+ const verdict = this.check();
6426
+ if (verdict.usable) {
6427
+ this.held.clear();
6428
+ return null;
6429
+ }
6430
+ return {
6431
+ reason: verdict.reason,
6432
+ deferred_agents: [...this.held.keys()].sort(),
6433
+ blocked_since: new Date(Math.min(...this.held.values())).toISOString()
6434
+ };
6435
+ }
6436
+ /** For tests and logs. */
6437
+ heldAgents() {
6438
+ return [...this.held.keys()].sort();
6439
+ }
6440
+ };
6441
+
6362
6442
  // src/lib/channel-sweep.ts
6363
6443
  import { execFileSync } from "child_process";
6364
6444
  var CHANNEL_BASENAMES = [
@@ -6927,7 +7007,7 @@ function planGlobalSkillSync(globalSkills, prevIds, hashOf, knownHash, options)
6927
7007
  }
6928
7008
 
6929
7009
  // src/lib/manager/integration-skill-cache.ts
6930
- import { join as join30 } from "path";
7010
+ import { join as join31 } from "path";
6931
7011
  function integrationSkillHashKey(agentId, skillId) {
6932
7012
  return `plugin-skill:${agentId}:${skillId}`;
6933
7013
  }
@@ -6943,21 +7023,21 @@ function forgetIntegrationSkill(cache2, agentId, skillId) {
6943
7023
  function removeIntegrationSkillFolder(opts) {
6944
7024
  forgetIntegrationSkill(opts.cache, opts.agentId, opts.entry);
6945
7025
  for (const dir of opts.dirs) {
6946
- opts.removeDir(join30(dir, opts.entry));
7026
+ opts.removeDir(join31(dir, opts.entry));
6947
7027
  }
6948
7028
  }
6949
7029
 
6950
7030
  // src/lib/manager/managed-skill-manifest.ts
6951
- import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
6952
- import { dirname as dirname8, join as join31 } from "path";
7031
+ import { existsSync as existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync25, writeFileSync as writeFileSync12 } from "fs";
7032
+ import { dirname as dirname8, join as join32 } from "path";
6953
7033
  var MANIFEST_VERSION = 1;
6954
7034
  function managedSkillManifestPath(agentRootDir) {
6955
- return join31(agentRootDir, "managed-skills.json");
7035
+ return join32(agentRootDir, "managed-skills.json");
6956
7036
  }
6957
7037
  function readManagedSkillManifest(path) {
6958
7038
  try {
6959
7039
  if (!existsSync13(path)) return /* @__PURE__ */ new Set();
6960
- const parsed = JSON.parse(readFileSync24(path, "utf-8"));
7040
+ const parsed = JSON.parse(readFileSync25(path, "utf-8"));
6961
7041
  const ids = Array.isArray(parsed?.globalSkillIds) ? parsed.globalSkillIds : [];
6962
7042
  return new Set(ids.filter((id) => typeof id === "string" && id.length > 0));
6963
7043
  } catch {
@@ -7087,8 +7167,8 @@ function resolveModelChain(refreshData) {
7087
7167
 
7088
7168
  // src/lib/manager/claude-auth.ts
7089
7169
  import { existsSync as existsSync14, rmSync as rmSync6 } from "fs";
7090
- import { join as join32 } from "path";
7091
- import { homedir as homedir13 } from "os";
7170
+ import { join as join33 } from "path";
7171
+ import { homedir as homedir14 } from "os";
7092
7172
  async function applyClaudeAuthToEnv(childEnv, label) {
7093
7173
  const apiKey = getApiKey();
7094
7174
  if (!apiKey) {
@@ -7100,9 +7180,9 @@ async function applyClaudeAuthToEnv(childEnv, label) {
7100
7180
  throw new Error("claude_auth_mode=api_key but /host/exchange returned no decrypted key");
7101
7181
  }
7102
7182
  childEnv.ANTHROPIC_API_KEY = exchange.anthropicApiKey;
7103
- const claudeDir = join32(homedir13(), ".claude");
7183
+ const claudeDir = join33(homedir14(), ".claude");
7104
7184
  for (const filename of [".credentials.json", "credentials.json"]) {
7105
- const p = join32(claudeDir, filename);
7185
+ const p = join33(claudeDir, filename);
7106
7186
  if (existsSync14(p)) {
7107
7187
  try {
7108
7188
  rmSync6(p, { force: true });
@@ -7458,19 +7538,19 @@ function formatBoardForPrompt(items, template) {
7458
7538
  }
7459
7539
 
7460
7540
  // src/lib/manager/kanban/nudge-state-cache.ts
7461
- import { existsSync as existsSync15, readFileSync as readFileSync25, writeFileSync as writeFileSync13 } from "fs";
7462
- import { join as join33 } from "path";
7541
+ import { existsSync as existsSync15, readFileSync as readFileSync26, writeFileSync as writeFileSync13 } from "fs";
7542
+ import { join as join34 } from "path";
7463
7543
  var CACHE_FILENAME2 = "kanban-nudge-state.json";
7464
7544
  var KANBAN_NUDGE_STATE_VERSION = 1;
7465
7545
  function getKanbanNudgeStateFile(configDir) {
7466
- return join33(configDir, CACHE_FILENAME2);
7546
+ return join34(configDir, CACHE_FILENAME2);
7467
7547
  }
7468
7548
  function loadKanbanNudgeState(target, configDir) {
7469
7549
  const path = getKanbanNudgeStateFile(configDir);
7470
7550
  if (!existsSync15(path)) return;
7471
7551
  let parsed;
7472
7552
  try {
7473
- parsed = JSON.parse(readFileSync25(path, "utf-8"));
7553
+ parsed = JSON.parse(readFileSync26(path, "utf-8"));
7474
7554
  } catch {
7475
7555
  return;
7476
7556
  }
@@ -8088,9 +8168,9 @@ function closeSessionRunForCode(codeName, outcome, reason) {
8088
8168
 
8089
8169
  // src/lib/manager/scheduler/kanban-route.ts
8090
8170
  import { createHash as createHash15 } from "crypto";
8091
- import { writeFileSync as writeFileSync14, renameSync as renameSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync26, unlinkSync as unlinkSync3 } from "fs";
8092
- import { homedir as homedir14 } from "os";
8093
- import { join as join34, dirname as dirname9 } from "path";
8171
+ import { writeFileSync as writeFileSync14, renameSync as renameSync8, mkdirSync as mkdirSync11, readFileSync as readFileSync27, unlinkSync as unlinkSync3 } from "fs";
8172
+ import { homedir as homedir15 } from "os";
8173
+ import { join as join35, dirname as dirname9 } from "path";
8094
8174
 
8095
8175
  // src/lib/manager/scheduler/notify.ts
8096
8176
  import { createHash as createHash14 } from "crypto";
@@ -8449,7 +8529,7 @@ function resolveScheduledSlackTarget(task) {
8449
8529
  }
8450
8530
  function stampScheduledTurnMarker(codeName, taskId, target) {
8451
8531
  try {
8452
- const file = join34(homedir14(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
8532
+ const file = join35(homedir15(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
8453
8533
  const marker = { ts: Date.now(), task_id: taskId, ...target ? { target } : {} };
8454
8534
  const tmp = `${file}.tmp`;
8455
8535
  writeFileSync14(tmp, JSON.stringify(marker), "utf8");
@@ -8459,9 +8539,9 @@ function stampScheduledTurnMarker(codeName, taskId, target) {
8459
8539
  }
8460
8540
  }
8461
8541
  function clearScheduledTurnMarkerForTask(codeName, taskId) {
8462
- const file = join34(homedir14(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
8542
+ const file = join35(homedir15(), ".augmented", codeName, SCHEDULED_TURN_MARKER_FILENAME);
8463
8543
  try {
8464
- const raw = JSON.parse(readFileSync26(file, "utf8"));
8544
+ const raw = JSON.parse(readFileSync27(file, "utf8"));
8465
8545
  if (typeof raw?.task_id !== "string" || raw.task_id !== taskId) return;
8466
8546
  unlinkSync3(file);
8467
8547
  log(`[scheduled-kanban] scheduled-turn marker cleared for '${codeName}' (task ${taskId} complete)`);
@@ -8521,7 +8601,7 @@ async function routeScheduledTaskViaKanban(codeName, agentId, task, prompt, dura
8521
8601
  return false;
8522
8602
  }
8523
8603
  try {
8524
- const doorbell = directChatDoorbellPath(agentId, homedir14());
8604
+ const doorbell = directChatDoorbellPath(agentId, homedir15());
8525
8605
  mkdirSync11(dirname9(doorbell), { recursive: true });
8526
8606
  writeFileSync14(doorbell, String(Date.now()));
8527
8607
  } catch (err) {
@@ -8673,12 +8753,12 @@ async function processClaudeTaskResult(codeName, agentId, templateId, rawOutput,
8673
8753
 
8674
8754
  // src/lib/manager/scheduler/execution.ts
8675
8755
  import { createHash as createHash16 } from "crypto";
8676
- import { homedir as homedir15 } from "os";
8677
- import { join as join36 } from "path";
8756
+ import { homedir as homedir16 } from "os";
8757
+ import { join as join37 } from "path";
8678
8758
 
8679
8759
  // src/lib/agent-serving-probe.ts
8680
- import { readFileSync as readFileSync27, readdirSync as readdirSync8, statSync as statSync8 } from "fs";
8681
- import { join as join35 } from "path";
8760
+ import { readFileSync as readFileSync28, readdirSync as readdirSync8, statSync as statSync9 } from "fs";
8761
+ import { join as join36 } from "path";
8682
8762
  var RATE_LIMIT_WINDOW_MS = 6 * 60 * 60 * 1e3;
8683
8763
  function probeRateLimit(args) {
8684
8764
  const now = args.now ?? /* @__PURE__ */ new Date();
@@ -8694,16 +8774,16 @@ function probeRateLimit(args) {
8694
8774
  let newest = UNKNOWN_RATE_LIMIT;
8695
8775
  for (const name of entries) {
8696
8776
  if (!name.endsWith(".jsonl")) continue;
8697
- const path = join35(dir, name);
8777
+ const path = join36(dir, name);
8698
8778
  try {
8699
- const st = statSync8(path);
8779
+ const st = statSync9(path);
8700
8780
  if (!st.isFile() || st.mtimeMs < startMs) continue;
8701
8781
  } catch {
8702
8782
  continue;
8703
8783
  }
8704
8784
  let content;
8705
8785
  try {
8706
- content = readFileSync27(path, "utf-8");
8786
+ content = readFileSync28(path, "utf-8");
8707
8787
  } catch {
8708
8788
  continue;
8709
8789
  }
@@ -8765,7 +8845,7 @@ function shouldLogUsageCapDeferral(site, codeName, limitedUntil) {
8765
8845
 
8766
8846
  // src/lib/manager/scheduler/execution.ts
8767
8847
  function claudePidFilePath() {
8768
- return join36(homedir15(), ".augmented", "manager-claude-pids.json");
8848
+ return join37(homedir16(), ".augmented", "manager-claude-pids.json");
8769
8849
  }
8770
8850
  var inFlightClaudePids = /* @__PURE__ */ new Map();
8771
8851
  function registerClaudeSpawn(record) {
@@ -8835,8 +8915,8 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
8835
8915
  }
8836
8916
 
8837
8917
  // src/lib/occupancy-gate.ts
8838
- import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync9, readSync as readSync2, statSync as statSync9 } from "fs";
8839
- import { join as join37 } from "path";
8918
+ import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync9, readSync as readSync2, statSync as statSync10 } from "fs";
8919
+ import { join as join38 } from "path";
8840
8920
  function rostersMeasuredZero(mode, attested, runtimeRunning) {
8841
8921
  return mode === "enforce" && attested && runtimeRunning;
8842
8922
  }
@@ -8850,7 +8930,7 @@ var brackets = /* @__PURE__ */ new Map();
8850
8930
  function readAlignedTail(path, tailBytes, maxAlignBytes) {
8851
8931
  let fd = null;
8852
8932
  try {
8853
- const size = statSync9(path).size;
8933
+ const size = statSync10(path).size;
8854
8934
  if (size <= 0) return { content: "", complete: true, truncated: false };
8855
8935
  fd = openSync2(path, "r");
8856
8936
  let readStart = Math.max(0, size - tailBytes);
@@ -8927,10 +9007,10 @@ function candidateTranscriptPaths(dir) {
8927
9007
  let complete = true;
8928
9008
  for (const name of top) {
8929
9009
  if (name.endsWith(".jsonl")) {
8930
- paths.push(join37(dir, name));
9010
+ paths.push(join38(dir, name));
8931
9011
  continue;
8932
9012
  }
8933
- const subDir = join37(dir, name, "subagents");
9013
+ const subDir = join38(dir, name, "subagents");
8934
9014
  let subs;
8935
9015
  try {
8936
9016
  subs = readdirSync9(subDir);
@@ -8939,7 +9019,7 @@ function candidateTranscriptPaths(dir) {
8939
9019
  continue;
8940
9020
  }
8941
9021
  for (const sub of subs) {
8942
- if (sub.endsWith(".jsonl")) paths.push(join37(subDir, sub));
9022
+ if (sub.endsWith(".jsonl")) paths.push(join38(subDir, sub));
8943
9023
  }
8944
9024
  }
8945
9025
  return { paths, complete };
@@ -8994,7 +9074,7 @@ function collectQualifyingTurns(codeName, nowMs, opts = {}) {
8994
9074
  for (const path of paths) {
8995
9075
  let st;
8996
9076
  try {
8997
- st = statSync9(path);
9077
+ st = statSync10(path);
8998
9078
  } catch (err) {
8999
9079
  if (!isAbsentDirError(err)) complete = false;
9000
9080
  continue;
@@ -9100,7 +9180,7 @@ function qualifyBuckets(buckets, qualifying, mode, nowMs, neighbourhoodMs = DEFA
9100
9180
  }
9101
9181
 
9102
9182
  // src/lib/pane-occupancy-sampler.ts
9103
- import { statSync as statSync10 } from "fs";
9183
+ import { statSync as statSync11 } from "fs";
9104
9184
  var SAMPLE_INTERVAL_MS = 1e4;
9105
9185
  var IDLE_GAP_MS = 12e4;
9106
9186
  var POST_IDLE_CREDIT_MS = 6e4;
@@ -9114,7 +9194,7 @@ function hasFreshPaneObservation(codeName, nowMs, maxAgeMs = OBSERVATION_FRESH_M
9114
9194
  }
9115
9195
  function paneMtimeMs(codeName) {
9116
9196
  try {
9117
- return statSync10(paneLogPath(codeName)).mtimeMs;
9197
+ return statSync11(paneLogPath(codeName)).mtimeMs;
9118
9198
  } catch {
9119
9199
  return null;
9120
9200
  }
@@ -9165,7 +9245,7 @@ function stopPaneOccupancySampler() {
9165
9245
  }
9166
9246
 
9167
9247
  // src/lib/pid-pressure-sampler.ts
9168
- import { existsSync as existsSync16, readFileSync as readFileSync28 } from "fs";
9248
+ import { existsSync as existsSync16, readFileSync as readFileSync29 } from "fs";
9169
9249
  var SAMPLE_INTERVAL_MS2 = 3e4;
9170
9250
  function warnFraction() {
9171
9251
  const raw = Number(process.env.AGT_PID_PRESSURE_WARN_FRACTION);
@@ -9178,7 +9258,7 @@ function configuredCeiling() {
9178
9258
  }
9179
9259
  function readTextReal(path) {
9180
9260
  try {
9181
- return readFileSync28(path, "utf-8");
9261
+ return readFileSync29(path, "utf-8");
9182
9262
  } catch {
9183
9263
  return null;
9184
9264
  }
@@ -10495,9 +10575,9 @@ async function fireOpencodeScheduledTask(agent, task) {
10495
10575
 
10496
10576
  // src/lib/opencode-telegram-ingest.ts
10497
10577
  import { createHash as createHash19 } from "crypto";
10498
- import { existsSync as existsSync17, mkdirSync as mkdirSync12, readFileSync as readFileSync29, renameSync as renameSync9, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "fs";
10578
+ import { existsSync as existsSync17, mkdirSync as mkdirSync12, readFileSync as readFileSync30, renameSync as renameSync9, unlinkSync as unlinkSync4, writeFileSync as writeFileSync15 } from "fs";
10499
10579
  import { randomUUID } from "crypto";
10500
- import { join as join38 } from "path";
10580
+ import { join as join39 } from "path";
10501
10581
 
10502
10582
  // src/lib/telegram-ingest.ts
10503
10583
  import https2 from "https";
@@ -11054,7 +11134,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
11054
11134
  let filePath;
11055
11135
  try {
11056
11136
  dir = getFramework("opencode").getAgentDir(codeName);
11057
- filePath = join38(dir, "telegram-getupdates-offset-opencode.json");
11137
+ filePath = join39(dir, "telegram-getupdates-offset-opencode.json");
11058
11138
  } catch {
11059
11139
  dir = null;
11060
11140
  filePath = null;
@@ -11063,7 +11143,7 @@ function createFileOffsetStore(codeName, log2, currentBotId) {
11063
11143
  load() {
11064
11144
  if (!filePath) return 0;
11065
11145
  try {
11066
- const parsed = JSON.parse(readFileSync29(filePath, "utf-8"));
11146
+ const parsed = JSON.parse(readFileSync30(filePath, "utf-8"));
11067
11147
  if (currentBotId != null && typeof parsed?.bot_id === "number" && parsed.bot_id !== currentBotId) {
11068
11148
  log2(`[telegram-ingest:${codeName}] offset cursor belongs to a different bot; ignoring (bot swap)`);
11069
11149
  return 0;
@@ -11337,15 +11417,15 @@ function partitionActionableByPoison(actionable, states, config2) {
11337
11417
  }
11338
11418
 
11339
11419
  // src/lib/restart-flags.ts
11340
- import { existsSync as existsSync18, mkdirSync as mkdirSync13, readdirSync as readdirSync10, readFileSync as readFileSync30, renameSync as renameSync10, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "fs";
11341
- import { homedir as homedir16 } from "os";
11342
- import { join as join39 } from "path";
11420
+ import { existsSync as existsSync18, mkdirSync as mkdirSync13, readdirSync as readdirSync10, readFileSync as readFileSync31, renameSync as renameSync10, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "fs";
11421
+ import { homedir as homedir17 } from "os";
11422
+ import { join as join40 } from "path";
11343
11423
  import { randomUUID as randomUUID2 } from "crypto";
11344
11424
  function restartFlagsDir() {
11345
- return join39(homedir16(), ".augmented", "restart-flags");
11425
+ return join40(homedir17(), ".augmented", "restart-flags");
11346
11426
  }
11347
11427
  function flagPath(codeName) {
11348
- return join39(restartFlagsDir(), `${codeName}.flag`);
11428
+ return join40(restartFlagsDir(), `${codeName}.flag`);
11349
11429
  }
11350
11430
  function readRestartFlags() {
11351
11431
  const dir = restartFlagsDir();
@@ -11354,7 +11434,7 @@ function readRestartFlags() {
11354
11434
  for (const entry of readdirSync10(dir)) {
11355
11435
  if (!entry.endsWith(".flag")) continue;
11356
11436
  try {
11357
- const raw = readFileSync30(join39(dir, entry), "utf8");
11437
+ const raw = readFileSync31(join40(dir, entry), "utf8");
11358
11438
  const parsed = JSON.parse(raw);
11359
11439
  if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
11360
11440
  parsed.codeName = entry.replace(/\.flag$/, "");
@@ -11472,8 +11552,8 @@ async function sendError(flag, opts, text) {
11472
11552
  }
11473
11553
 
11474
11554
  // src/lib/restart-context.ts
11475
- import { readdirSync as readdirSync11, readFileSync as readFileSync31, writeFileSync as writeFileSync17, mkdirSync as mkdirSync14, unlinkSync as unlinkSync5 } from "fs";
11476
- import { dirname as dirname10, join as join40 } from "path";
11555
+ import { readdirSync as readdirSync11, readFileSync as readFileSync32, writeFileSync as writeFileSync17, mkdirSync as mkdirSync14, unlinkSync as unlinkSync5 } from "fs";
11556
+ import { dirname as dirname10, join as join41 } from "path";
11477
11557
  var SLACK_PENDING_INBOUND_DIRNAME = "slack-pending-inbound";
11478
11558
  var SLACK_RESTART_CONTEXT_DIRNAME = "slack-restart-context";
11479
11559
  var MAX_TOPIC_CHARS = 140;
@@ -11485,10 +11565,10 @@ function augmentedAgentDir(codeName) {
11485
11565
  return dirname10(getProjectDir(codeName));
11486
11566
  }
11487
11567
  function slackPendingInboundDir(codeName) {
11488
- return join40(augmentedAgentDir(codeName), SLACK_PENDING_INBOUND_DIRNAME);
11568
+ return join41(augmentedAgentDir(codeName), SLACK_PENDING_INBOUND_DIRNAME);
11489
11569
  }
11490
11570
  function slackRestartContextDir(codeName) {
11491
- return join40(augmentedAgentDir(codeName), SLACK_RESTART_CONTEXT_DIRNAME);
11571
+ return join41(augmentedAgentDir(codeName), SLACK_RESTART_CONTEXT_DIRNAME);
11492
11572
  }
11493
11573
  function sanitizeTopic(raw) {
11494
11574
  const cleaned = raw.replace(/\s+/g, " ").trim().replace(/[<>]/g, " ").replace(/\s+/g, " ").trim();
@@ -11530,7 +11610,7 @@ function safeReaddir(dir) {
11530
11610
  }
11531
11611
  function readStrandedMarker(path) {
11532
11612
  try {
11533
- const parsed = JSON.parse(readFileSync31(path, "utf-8"));
11613
+ const parsed = JSON.parse(readFileSync32(path, "utf-8"));
11534
11614
  if (typeof parsed.channel === "string" && typeof parsed.thread_ts === "string") {
11535
11615
  return { channel: parsed.channel, thread_ts: parsed.thread_ts };
11536
11616
  }
@@ -11548,7 +11628,7 @@ function pruneHintsExcept(codeName, freshFilenames) {
11548
11628
  if (!filename.endsWith(".json")) continue;
11549
11629
  if (freshFilenames.has(filename)) continue;
11550
11630
  try {
11551
- unlinkSync5(join40(ctxDir, filename));
11631
+ unlinkSync5(join41(ctxDir, filename));
11552
11632
  } catch {
11553
11633
  }
11554
11634
  }
@@ -11569,7 +11649,7 @@ function refreshSlackRestartContextHints(codeNames, opts = {}) {
11569
11649
  }
11570
11650
  const markers = [];
11571
11651
  for (const filename of markerFilenames.slice(0, cap)) {
11572
- const parsed = readStrandedMarker(join40(markerDir, filename));
11652
+ const parsed = readStrandedMarker(join41(markerDir, filename));
11573
11653
  if (parsed) markers.push({ filename, channel: parsed.channel, thread_ts: parsed.thread_ts });
11574
11654
  }
11575
11655
  if (markers.length === 0) {
@@ -11583,7 +11663,7 @@ function refreshSlackRestartContextHints(codeNames, opts = {}) {
11583
11663
  const freshFilenames = /* @__PURE__ */ new Set();
11584
11664
  for (const { filename, hint } of hints) {
11585
11665
  try {
11586
- writeHintFile(join40(ctxDir, filename), ctxDir, hint);
11666
+ writeHintFile(join41(ctxDir, filename), ctxDir, hint);
11587
11667
  freshFilenames.add(filename);
11588
11668
  } catch (err) {
11589
11669
  log2(`[restart-context] ${codeName}: hint write failed for ${filename}: ${err.message}`);
@@ -13094,6 +13174,7 @@ function decideDayRolloverAction(i) {
13094
13174
  if (age !== null && age !== void 0 && age < graceSec && heldMin < maxHoldMin) {
13095
13175
  return "inbound-wait";
13096
13176
  }
13177
+ if (i.deviceStateReady === false) return "defer-device-state";
13097
13178
  return "force-reset";
13098
13179
  }
13099
13180
  function classifyLazyDayRolloverReset(i) {
@@ -13101,7 +13182,19 @@ function classifyLazyDayRolloverReset(i) {
13101
13182
  if (!i.sessionHealthy) return "clear-stale";
13102
13183
  if (!i.staleForToday) return "clear-stale";
13103
13184
  if (!i.hasCurrent) return "skip";
13104
- return i.idle ? "reset" : "skip";
13185
+ if (!i.idle) return "skip";
13186
+ return i.deviceStateReady === false ? "defer-device-state" : "reset";
13187
+ }
13188
+ var deviceStateRotationGate = new DeviceStateRotationGate();
13189
+ function deviceStateAllowsRollover(codeName, path) {
13190
+ const gate = deviceStateRotationGate.mayRotate(codeName, Date.now());
13191
+ if (gate.ready) return true;
13192
+ if (gate.firstHold) {
13193
+ log(
13194
+ `[persistent-session] Day rollover for '${codeName}' HELD (${path}) \u2014 the host's ~/.claude.json is not usable (${gate.reason}), so a fresh session would land on the login picker. Keeping the working session; the rotation runs the first tick the file is usable again. Pair the host from the Hosts page. (further holds this episode are not logged) [ENG-10351]`
13195
+ );
13196
+ }
13197
+ return false;
13105
13198
  }
13106
13199
  function resolveEffectiveAgentTimezone(inputs) {
13107
13200
  const orgTierTz = cachedMaintenanceWindow?.timezone ?? null;
@@ -13130,18 +13223,22 @@ function performLazyDayRolloverReset(codeName, agentTimezone) {
13130
13223
  const sessionHealthy = flagged && isSessionHealthy(codeName);
13131
13224
  const staleForToday = flagged ? isStaleForToday(codeName, /* @__PURE__ */ new Date(), agentTimezone ?? void 0) : false;
13132
13225
  const current = flagged && sessionHealthy && staleForToday ? peekCurrentSession(codeName) : null;
13133
- const outcome = classifyLazyDayRolloverReset({
13226
+ const lazyInputs = {
13134
13227
  flagged,
13135
13228
  staleForToday,
13136
13229
  sessionHealthy,
13137
13230
  hasCurrent: current !== null,
13138
13231
  idle: current ? isAgentIdle(getProjectDir(codeName), current.sessionId) : false
13139
- });
13232
+ };
13233
+ let outcome = classifyLazyDayRolloverReset(lazyInputs);
13234
+ if (outcome === "reset" && !deviceStateAllowsRollover(codeName, "lazy-reset")) {
13235
+ outcome = classifyLazyDayRolloverReset({ ...lazyInputs, deviceStateReady: false });
13236
+ }
13140
13237
  if (outcome === "clear-stale") {
13141
13238
  pendingDayRolloverReset.delete(codeName);
13142
13239
  return false;
13143
13240
  }
13144
- if (outcome === "skip" || !current) return false;
13241
+ if (outcome !== "reset" || !current) return false;
13145
13242
  log(
13146
13243
  `[persistent-session] Day rollover for '${codeName}' (yesterday=${current.date}) \u2014 first real trigger after an idle rollover; minting a fresh session now (deferred boot, paid alongside real work) [ENG-8461]`
13147
13244
  );
@@ -13153,7 +13250,7 @@ function performLazyDayRolloverReset(codeName, agentTimezone) {
13153
13250
  }
13154
13251
  function paneLogAgeSecondsFor(codeName) {
13155
13252
  try {
13156
- const mtimeMs = statSync11(paneLogPath(codeName)).mtimeMs;
13253
+ const mtimeMs = statSync12(paneLogPath(codeName)).mtimeMs;
13157
13254
  return Math.max(0, Math.floor((Date.now() - mtimeMs) / 1e3));
13158
13255
  } catch (err) {
13159
13256
  if (err?.code === "ENOENT") return null;
@@ -13303,7 +13400,7 @@ var runningChannelSecretHashes = /* @__PURE__ */ new Map();
13303
13400
  var sessionLaunchManagedStructure = /* @__PURE__ */ new Map();
13304
13401
  function projectMcpHash(_codeName, projectDir) {
13305
13402
  try {
13306
- const raw = readFileSync32(join41(projectDir, ".mcp.json"), "utf-8");
13403
+ const raw = readFileSync33(join42(projectDir, ".mcp.json"), "utf-8");
13307
13404
  return createHash20("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
13308
13405
  } catch {
13309
13406
  return null;
@@ -13311,7 +13408,7 @@ function projectMcpHash(_codeName, projectDir) {
13311
13408
  }
13312
13409
  function projectMcpKeys(_codeName, projectDir) {
13313
13410
  try {
13314
- const raw = readFileSync32(join41(projectDir, ".mcp.json"), "utf-8");
13411
+ const raw = readFileSync33(join42(projectDir, ".mcp.json"), "utf-8");
13315
13412
  const parsed = JSON.parse(raw);
13316
13413
  const servers = parsed.mcpServers;
13317
13414
  if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
@@ -13329,7 +13426,7 @@ function seedSessionLaunchBaselines(codeName, projectDir) {
13329
13426
  else runningMcpServerKeys.delete(codeName);
13330
13427
  let launchStructure = null;
13331
13428
  try {
13332
- const raw = readFileSync32(join41(projectDir, ".mcp.json"), "utf-8");
13429
+ const raw = readFileSync33(join42(projectDir, ".mcp.json"), "utf-8");
13333
13430
  launchStructure = managedMcpStructureHashFromFile(
13334
13431
  JSON.parse(raw),
13335
13432
  isManagedMcpServerKey
@@ -13464,7 +13561,7 @@ async function runAgentSessionToolBindProbes(agent, integrations, projectDir, op
13464
13561
  if (result && result.rebindCandidates.length > 0 && hostFlagStore().getBoolean("session-tool-rebind")) {
13465
13562
  let mcpJsonForRebind = null;
13466
13563
  try {
13467
- mcpJsonForRebind = JSON.parse(readFileSync32(join41(projectDir, ".mcp.json"), "utf-8"));
13564
+ mcpJsonForRebind = JSON.parse(readFileSync33(join42(projectDir, ".mcp.json"), "utf-8"));
13468
13565
  } catch {
13469
13566
  mcpJsonForRebind = null;
13470
13567
  }
@@ -13612,7 +13709,7 @@ function shouldInjectChannelSecrets(agentId) {
13612
13709
  function projectChannelSecretHash(projectDir) {
13613
13710
  try {
13614
13711
  const entries = parseEnvIntegrations(
13615
- readFileSync32(join41(projectDir, ".env.integrations"), "utf-8")
13712
+ readFileSync33(join42(projectDir, ".env.integrations"), "utf-8")
13616
13713
  );
13617
13714
  return channelSecretValueHash(entries, CHANNEL_SECRET_ENV_KEYS);
13618
13715
  } catch {
@@ -13721,7 +13818,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13721
13818
  var lastVersionCheckAt = 0;
13722
13819
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13723
13820
  var lastResponsivenessProbeAt = 0;
13724
- var agtCliVersion = true ? "0.28.906" : "dev";
13821
+ var agtCliVersion = true ? "0.28.908" : "dev";
13725
13822
  function resolveBrewPath(execFileSync2) {
13726
13823
  try {
13727
13824
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14055,7 +14152,7 @@ function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
14055
14152
  try {
14056
14153
  let settings = {};
14057
14154
  if (existsSync19(path)) {
14058
- const raw = readFileSync32(path, "utf-8").trim();
14155
+ const raw = readFileSync33(path, "utf-8").trim();
14059
14156
  if (raw) {
14060
14157
  let parsed;
14061
14158
  try {
@@ -14111,7 +14208,7 @@ async function ensureOpencodeBinary() {
14111
14208
  try {
14112
14209
  const prefix = execFileSync2("npm", ["prefix", "-g"], { encoding: "utf-8", timeout: 1e4 }).trim();
14113
14210
  if (prefix) {
14114
- const npmBin = join41(prefix, "bin");
14211
+ const npmBin = join42(prefix, "bin");
14115
14212
  const current = (process.env.PATH ?? "").split(pathDelimiter);
14116
14213
  if (!current.includes(npmBin)) {
14117
14214
  process.env.PATH = [npmBin, ...current.filter(Boolean)].join(pathDelimiter);
@@ -14251,7 +14348,7 @@ async function maybeUpgradeClaudeCode() {
14251
14348
  }
14252
14349
  var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
14253
14350
  function selfUpdateAppliedMarkerPath() {
14254
- return join41(homedir17(), ".augmented", ".last-self-update-applied");
14351
+ return join42(homedir18(), ".augmented", ".last-self-update-applied");
14255
14352
  }
14256
14353
  var selfUpdateUpToDateLogged = false;
14257
14354
  var selfUpdatePinnedLogged = false;
@@ -14302,7 +14399,7 @@ async function checkAndUpdateCli(opts) {
14302
14399
  const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
14303
14400
  if (!isBrewFormula && !isNpmGlobal) return "noop";
14304
14401
  const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
14305
- const markerPath = join41(homedir17(), ".augmented", ".last-update-check");
14402
+ const markerPath = join42(homedir18(), ".augmented", ".last-update-check");
14306
14403
  if (!force) {
14307
14404
  try {
14308
14405
  const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
@@ -14709,7 +14806,7 @@ async function runClaudeRuntimeAuthProbe() {
14709
14806
  ];
14710
14807
  try {
14711
14808
  const { stdout, stderr } = await execFilePromiseLong(resolveClaudeBinary(), args, {
14712
- cwd: homedir17(),
14809
+ cwd: homedir18(),
14713
14810
  timeout: RUNTIME_AUTH_PROBE_TIMEOUT_MS,
14714
14811
  stdin: "ignore",
14715
14812
  env: childEnv,
@@ -14749,7 +14846,7 @@ async function runHostUsageCommand() {
14749
14846
  ""
14750
14847
  ];
14751
14848
  const { stdout } = await execFilePromiseLong(resolveClaudeBinary(), args, {
14752
- cwd: homedir17(),
14849
+ cwd: homedir18(),
14753
14850
  timeout: HOST_USAGE_POLL_TIMEOUT_MS,
14754
14851
  stdin: "ignore",
14755
14852
  env: childEnv,
@@ -14796,12 +14893,12 @@ async function checkClaudeAuth() {
14796
14893
  var evalEmptyMcpConfigPath = null;
14797
14894
  function ensureEvalEmptyMcpConfig() {
14798
14895
  if (evalEmptyMcpConfigPath && existsSync19(evalEmptyMcpConfigPath)) return evalEmptyMcpConfigPath;
14799
- const dir = join41(homedir17(), ".augmented");
14896
+ const dir = join42(homedir18(), ".augmented");
14800
14897
  try {
14801
14898
  mkdirSync15(dir, { recursive: true });
14802
14899
  } catch {
14803
14900
  }
14804
- const p = join41(dir, ".eval-empty-mcp.json");
14901
+ const p = join42(dir, ".eval-empty-mcp.json");
14805
14902
  writeFileSync18(p, JSON.stringify({ mcpServers: {} }));
14806
14903
  evalEmptyMcpConfigPath = p;
14807
14904
  return p;
@@ -14827,7 +14924,7 @@ async function runEvalClaude(prompt, model) {
14827
14924
  ""
14828
14925
  ];
14829
14926
  const { stdout } = await execFilePromiseLong(resolveClaudeBinary(), args, {
14830
- cwd: homedir17(),
14927
+ cwd: homedir18(),
14831
14928
  timeout: 12e4,
14832
14929
  stdin: "ignore",
14833
14930
  env: childEnv,
@@ -14896,10 +14993,10 @@ function resolveConversationEvalBackend() {
14896
14993
  return conversationEvalBackend;
14897
14994
  }
14898
14995
  function getStateFile() {
14899
- return join41(config?.configDir ?? join41(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
14996
+ return join42(config?.configDir ?? join42(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
14900
14997
  }
14901
14998
  function channelHashCacheDir() {
14902
- return config?.configDir ?? join41(process.env["HOME"] ?? "/tmp", ".augmented");
14999
+ return config?.configDir ?? join42(process.env["HOME"] ?? "/tmp", ".augmented");
14903
15000
  }
14904
15001
  function loadChannelHashCache2() {
14905
15002
  loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
@@ -15112,7 +15209,7 @@ function removeDeliveryBaselineEntries(agentId) {
15112
15209
  var _channelQuarantineStore = null;
15113
15210
  function channelQuarantineStore() {
15114
15211
  if (!_channelQuarantineStore) {
15115
- const dir = config?.configDir ?? join41(process.env["HOME"] ?? "/tmp", ".augmented");
15212
+ const dir = config?.configDir ?? join42(process.env["HOME"] ?? "/tmp", ".augmented");
15116
15213
  _channelQuarantineStore = new ChannelQuarantineStore(defaultQuarantinePath(dir));
15117
15214
  }
15118
15215
  return _channelQuarantineStore;
@@ -15128,12 +15225,12 @@ function claudeMdSizeFor(codeName) {
15128
15225
  }
15129
15226
  function forwardedToolsFor(codeName) {
15130
15227
  if (!config?.configDir) return null;
15131
- return readForwardedToolsReport(join41(config.configDir, codeName));
15228
+ return readForwardedToolsReport(join42(config.configDir, codeName));
15132
15229
  }
15133
15230
  var _hostFlagStore = null;
15134
15231
  function hostFlagStore() {
15135
15232
  if (!_hostFlagStore) {
15136
- const dir = config?.configDir ?? join41(process.env["HOME"] ?? "/tmp", ".augmented");
15233
+ const dir = config?.configDir ?? join42(process.env["HOME"] ?? "/tmp", ".augmented");
15137
15234
  _hostFlagStore = new HostFlagStore({ cachePath: defaultFlagsCachePath(dir), log });
15138
15235
  }
15139
15236
  return _hostFlagStore;
@@ -15207,12 +15304,12 @@ function parseSkillFrontmatter(content) {
15207
15304
  }
15208
15305
  async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
15209
15306
  const { readdirSync: readdirSync13, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync19 } = await import("fs");
15210
- const skillsDir = join41(configDir, codeName, "project", ".claude", "skills");
15211
- const claudeMdPath = join41(configDir, codeName, "project", "CLAUDE.md");
15307
+ const skillsDir = join42(configDir, codeName, "project", ".claude", "skills");
15308
+ const claudeMdPath = join42(configDir, codeName, "project", "CLAUDE.md");
15212
15309
  if (!ex(skillsDir) || !ex(claudeMdPath)) return;
15213
15310
  const entries = [];
15214
15311
  for (const dir of readdirSync13(skillsDir).sort()) {
15215
- const skillFile = join41(skillsDir, dir, "SKILL.md");
15312
+ const skillFile = join42(skillsDir, dir, "SKILL.md");
15216
15313
  if (!ex(skillFile)) continue;
15217
15314
  try {
15218
15315
  const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
@@ -15570,6 +15667,12 @@ async function pollCycleInner() {
15570
15667
  // customer agents had been dark for three minutes. Bounding the retry
15571
15668
  // without this would fix the CPU and leave the blindness.
15572
15669
  realtime_rebind_stuck: stuckRealtimeRebinds(realtimeRebindFailures, Date.now()),
15670
+ // ENG-10351: ONE host-level verdict for rotations held because the
15671
+ // host's ~/.claude.json is not usable. ALWAYS sent: `null` is the
15672
+ // affirmative all-clear that lets the API close the alert on the edge,
15673
+ // and an absent field means an older CLI. Re-checks the file while a
15674
+ // hold exists, so pairing the host closes the alert on the next beat.
15675
+ claude_device_state_rotation_blocked: deviceStateRotationGate.heartbeatField(),
15573
15676
  // ENG-6251: capability advertisement — the flags schema version this
15574
15677
  // CLI compiled with, so the admin UI can show flip reach across a
15575
15678
  // mixed-CLI fleet (an older CLI sends an older fingerprint).
@@ -15828,13 +15931,13 @@ async function pollCycleInner() {
15828
15931
  );
15829
15932
  if (hostFlagStore().getBoolean("wedge-transient-notice")) {
15830
15933
  try {
15831
- const paneTail = readFileSync32(paneLogPath(codeName), "utf8").slice(-65536);
15934
+ const paneTail = readFileSync33(paneLogPath(codeName), "utf8").slice(-65536);
15832
15935
  const transient = detectTransientApiErrorInLog(paneTail);
15833
15936
  if (transient) {
15834
- const wedgeHome = join41(homedir17(), ".augmented", codeName);
15937
+ const wedgeHome = join42(homedir18(), ".augmented", codeName);
15835
15938
  if (existsSync19(wedgeHome)) {
15836
15939
  atomicWriteFileSync(
15837
- join41(wedgeHome, "watchdog-give-up.json"),
15940
+ join42(wedgeHome, "watchdog-give-up.json"),
15838
15941
  JSON.stringify({
15839
15942
  gave_up_at: wedgeNow.toISOString(),
15840
15943
  reason: "transient_overload"
@@ -16169,7 +16272,7 @@ async function pollCycleInner() {
16169
16272
  `[drain-flush] FAILED for '${prev.codeName}': ${err.message} \u2014 proceeding to teardown; this session was NOT shipped (ENG-9491)`
16170
16273
  );
16171
16274
  }
16172
- const agentDir = join41(adapter.getAgentDir(prev.codeName), "provision");
16275
+ const agentDir = join42(adapter.getAgentDir(prev.codeName), "provision");
16173
16276
  await cleanupAgentFiles(prev.codeName, agentDir);
16174
16277
  clearAgentCaches(prev.agentId, prev.codeName);
16175
16278
  }
@@ -16256,10 +16359,10 @@ async function pollCycleInner() {
16256
16359
  // pending-inbound marker. Best-effort: a write failure is logged by
16257
16360
  // the watchdog, never fails the poll cycle.
16258
16361
  signalGiveUp: (codeName) => {
16259
- const dir = join41(homedir17(), ".augmented", codeName);
16362
+ const dir = join42(homedir18(), ".augmented", codeName);
16260
16363
  if (!existsSync19(dir)) return;
16261
16364
  atomicWriteFileSync(
16262
- join41(dir, "watchdog-give-up.json"),
16365
+ join42(dir, "watchdog-give-up.json"),
16263
16366
  JSON.stringify({ gave_up_at: (/* @__PURE__ */ new Date()).toISOString() })
16264
16367
  );
16265
16368
  },
@@ -16280,7 +16383,7 @@ async function pollCycleInner() {
16280
16383
  const dir = getFramework("claude-code").getAgentDir(codeName);
16281
16384
  if (!existsSync19(dir)) return;
16282
16385
  atomicWriteFileSync(
16283
- join41(dir, "watchdog-give-up.json"),
16386
+ join42(dir, "watchdog-give-up.json"),
16284
16387
  JSON.stringify({
16285
16388
  gave_up_at: (/* @__PURE__ */ new Date()).toISOString(),
16286
16389
  reason: "usage_limit",
@@ -16548,7 +16651,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16548
16651
  }
16549
16652
  const now = (/* @__PURE__ */ new Date()).toISOString();
16550
16653
  const adapter = resolveAgentFramework(agent.code_name);
16551
- let agentDir = join41(adapter.getAgentDir(agent.code_name), "provision");
16654
+ let agentDir = join42(adapter.getAgentDir(agent.code_name), "provision");
16552
16655
  if (agent.status === "draft" || agent.status === "paused") {
16553
16656
  forgetChannelSyncState(agent.agent_id);
16554
16657
  if (previousKnownStatus !== agent.status) {
@@ -16695,7 +16798,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16695
16798
  if (refreshData.knowledge_manifest) {
16696
16799
  const resolved = await resolveKnowledgeFromManifest({
16697
16800
  manifest: refreshData.knowledge_manifest,
16698
- cacheDir: join41(config.configDir, "_knowledge"),
16801
+ cacheDir: join42(config.configDir, "_knowledge"),
16699
16802
  delivery: refreshData.agent?.knowledge_delivery ?? "both",
16700
16803
  fetchContents: async (hashes) => {
16701
16804
  const res = await api.post(
@@ -16712,7 +16815,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16712
16815
  const resolvedSkills = await resolveSkillsFromManifest({
16713
16816
  globals: refreshData.global_skills_manifest ?? [],
16714
16817
  shared: refreshData.shared_skills_manifest ?? [],
16715
- cacheDir: join41(config.configDir, "_skills"),
16818
+ cacheDir: join42(config.configDir, "_skills"),
16716
16819
  fetchContents: async (hashes) => {
16717
16820
  const res = await api.post(
16718
16821
  "/host/skills/contents",
@@ -16730,7 +16833,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16730
16833
  if (refreshData.integration_skills_manifest) {
16731
16834
  const resolvedIntegrationSkills = await resolveIntegrationSkillsFromManifest({
16732
16835
  manifest: refreshData.integration_skills_manifest,
16733
- cacheDir: join41(config.configDir, "_skills"),
16836
+ cacheDir: join42(config.configDir, "_skills"),
16734
16837
  fetchContents: async (hashes) => {
16735
16838
  const res = await api.post(
16736
16839
  "/host/skills/contents",
@@ -16792,7 +16895,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16792
16895
  const frameworkId = refreshData.agent.framework ?? DEFAULT_FRAMEWORK;
16793
16896
  agentFrameworkCache.set(agent.code_name, frameworkId);
16794
16897
  const frameworkAdapter = getFramework(frameworkId);
16795
- agentDir = join41(frameworkAdapter.getAgentDir(agent.code_name), "provision");
16898
+ agentDir = join42(frameworkAdapter.getAgentDir(agent.code_name), "provision");
16796
16899
  cacheAgentDeliveryMetadata(agent.code_name, refreshData);
16797
16900
  agentRestartTimezoneInputs.set(agent.code_name, {
16798
16901
  agentTimezone: typeof refreshData.agent.timezone === "string" ? refreshData.agent.timezone : null,
@@ -16851,7 +16954,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16851
16954
  const changedFiles = [];
16852
16955
  mkdirSync15(agentDir, { recursive: true });
16853
16956
  for (const artifact of artifacts) {
16854
- const filePath = join41(agentDir, artifact.relativePath);
16957
+ const filePath = join42(agentDir, artifact.relativePath);
16855
16958
  let existingHash;
16856
16959
  let newHash;
16857
16960
  let writeContent = artifact.content;
@@ -16870,8 +16973,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
16870
16973
  };
16871
16974
  newHash = sha256(stripDynamicSections(artifact.content));
16872
16975
  try {
16873
- const projectClaudeMd = join41(config.configDir, agent.code_name, "project", "CLAUDE.md");
16874
- const existing = readFileSync32(projectClaudeMd, "utf-8");
16976
+ const projectClaudeMd = join42(config.configDir, agent.code_name, "project", "CLAUDE.md");
16977
+ const existing = readFileSync33(projectClaudeMd, "utf-8");
16875
16978
  existingHash = sha256(stripDynamicSections(existing));
16876
16979
  } catch {
16877
16980
  existingHash = null;
@@ -16889,7 +16992,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16889
16992
  const generatorKeys = Object.keys(generatorServers);
16890
16993
  let existingRaw = "";
16891
16994
  try {
16892
- existingRaw = readFileSync32(filePath, "utf-8");
16995
+ existingRaw = readFileSync33(filePath, "utf-8");
16893
16996
  } catch {
16894
16997
  }
16895
16998
  const existingServers = parseMcp(existingRaw);
@@ -16905,7 +17008,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16905
17008
  } else if (artifact.relativePath === "opencode.json") {
16906
17009
  let existingRaw = null;
16907
17010
  try {
16908
- existingRaw = readFileSync32(filePath, "utf-8");
17011
+ existingRaw = readFileSync33(filePath, "utf-8");
16909
17012
  } catch {
16910
17013
  }
16911
17014
  const mergeResult = mergeOpencodeConfigArtifact(artifact.content, existingRaw);
@@ -16921,12 +17024,12 @@ async function processAgent(agent, agentStates, managedToolkits) {
16921
17024
  }
16922
17025
  }
16923
17026
  if (changedFiles.length > 0) {
16924
- const isFirst = !existsSync19(join41(agentDir, "CHARTER.md"));
17027
+ const isFirst = !existsSync19(join42(agentDir, "CHARTER.md"));
16925
17028
  const verb = isFirst ? "Provisioning" : "Updating";
16926
17029
  const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
16927
17030
  log(`${verb} '${agent.code_name}': ${fileNames}`);
16928
17031
  for (const file of changedFiles) {
16929
- const filePath = join41(agentDir, file.relativePath);
17032
+ const filePath = join42(agentDir, file.relativePath);
16930
17033
  mkdirSync15(dirname11(filePath), { recursive: true });
16931
17034
  if (file.relativePath === ".mcp.json") {
16932
17035
  safeWriteJsonAtomic(filePath, file.content, { mode: 384 });
@@ -16935,12 +17038,12 @@ async function processAgent(agent, agentStates, managedToolkits) {
16935
17038
  }
16936
17039
  }
16937
17040
  try {
16938
- const provSkillsDir = join41(agentDir, ".claude", "skills");
17041
+ const provSkillsDir = join42(agentDir, ".claude", "skills");
16939
17042
  if (existsSync19(provSkillsDir)) {
16940
17043
  for (const folder of readdirSync12(provSkillsDir)) {
16941
17044
  if (folder.startsWith("knowledge-")) {
16942
17045
  try {
16943
- rmSync8(join41(provSkillsDir, folder), { recursive: true });
17046
+ rmSync8(join42(provSkillsDir, folder), { recursive: true });
16944
17047
  } catch {
16945
17048
  }
16946
17049
  }
@@ -16953,7 +17056,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
16953
17056
  const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
16954
17057
  const hashes = /* @__PURE__ */ new Map();
16955
17058
  for (const file of trackedFiles2) {
16956
- const h = hashFile(join41(agentDir, file));
17059
+ const h = hashFile(join42(agentDir, file));
16957
17060
  if (h) hashes.set(file, h);
16958
17061
  }
16959
17062
  agentState.writtenHashes.set(agent.agent_id, hashes);
@@ -16971,14 +17074,14 @@ async function processAgent(agent, agentStates, managedToolkits) {
16971
17074
  }
16972
17075
  if (Array.isArray(refreshData.workflows)) {
16973
17076
  try {
16974
- const provWorkflowsDir = join41(agentDir, ".claude", "workflows");
17077
+ const provWorkflowsDir = join42(agentDir, ".claude", "workflows");
16975
17078
  if (existsSync19(provWorkflowsDir)) {
16976
17079
  const expected = new Set(refreshData.workflows.map((w) => `${w.name}.js`));
16977
17080
  for (const file of readdirSync12(provWorkflowsDir)) {
16978
17081
  if (!file.endsWith(".js")) continue;
16979
17082
  if (expected.has(file)) continue;
16980
17083
  try {
16981
- rmSync8(join41(provWorkflowsDir, file));
17084
+ rmSync8(join42(provWorkflowsDir, file));
16982
17085
  } catch {
16983
17086
  }
16984
17087
  }
@@ -17060,7 +17163,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17060
17163
  if (written && existsSync19(agentDir)) {
17061
17164
  const driftedFiles = [];
17062
17165
  for (const [file, expectedHash] of written) {
17063
- const localHash = hashFile(join41(agentDir, file));
17166
+ const localHash = hashFile(join42(agentDir, file));
17064
17167
  if (localHash && localHash !== expectedHash) {
17065
17168
  driftedFiles.push(file);
17066
17169
  }
@@ -17071,7 +17174,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17071
17174
  try {
17072
17175
  const localHashes = {};
17073
17176
  for (const file of driftedFiles) {
17074
- localHashes[file] = hashFile(join41(agentDir, file));
17177
+ localHashes[file] = hashFile(join42(agentDir, file));
17075
17178
  }
17076
17179
  await api.post("/host/drift", {
17077
17180
  agent_id: agent.agent_id,
@@ -17349,7 +17452,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17349
17452
  const addedChannels = [...restartDecision.added];
17350
17453
  const writeDmNoticeMarkers = isChannelAddRestart ? () => {
17351
17454
  try {
17352
- const agentAugmentedDir = join41(homedir17(), ".augmented", agent.code_name);
17455
+ const agentAugmentedDir = join42(homedir18(), ".augmented", agent.code_name);
17353
17456
  mkdirSync15(agentAugmentedDir, { recursive: true });
17354
17457
  const markerJson = JSON.stringify({
17355
17458
  version: 1,
@@ -17357,7 +17460,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17357
17460
  added: addedChannels
17358
17461
  });
17359
17462
  for (const file of ["slack-channel-add-restart.json", "telegram-channel-add-restart.json"]) {
17360
- atomicWriteFileSync(join41(agentAugmentedDir, file), markerJson);
17463
+ atomicWriteFileSync(join42(agentAugmentedDir, file), markerJson);
17361
17464
  }
17362
17465
  } catch (err) {
17363
17466
  log(`[hot-reload] channel-add DM-notice marker write failed for '${agent.code_name}' (non-fatal): ${err.message}`);
@@ -17656,18 +17759,18 @@ async function processAgent(agent, agentStates, managedToolkits) {
17656
17759
  if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? DEFAULT_FRAMEWORK) === "claude-code") {
17657
17760
  try {
17658
17761
  const agentProvisionDir = agentDir;
17659
- const projectDir = join41(homedir17(), ".augmented", agent.code_name, "project");
17762
+ const projectDir = join42(homedir18(), ".augmented", agent.code_name, "project");
17660
17763
  mkdirSync15(agentProvisionDir, { recursive: true });
17661
17764
  mkdirSync15(projectDir, { recursive: true });
17662
- const provisionMcpPath = join41(agentProvisionDir, ".mcp.json");
17663
- const projectMcpPath = join41(projectDir, ".mcp.json");
17765
+ const provisionMcpPath = join42(agentProvisionDir, ".mcp.json");
17766
+ const projectMcpPath = join42(projectDir, ".mcp.json");
17664
17767
  let mcpConfig = { mcpServers: {} };
17665
17768
  try {
17666
- mcpConfig = JSON.parse(readFileSync32(provisionMcpPath, "utf-8"));
17769
+ mcpConfig = JSON.parse(readFileSync33(provisionMcpPath, "utf-8"));
17667
17770
  if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
17668
17771
  } catch {
17669
17772
  }
17670
- const localDirectChatChannel = join41(homedir17(), ".augmented", "_mcp", "direct-chat-channel.js");
17773
+ const localDirectChatChannel = join42(homedir18(), ".augmented", "_mcp", "direct-chat-channel.js");
17671
17774
  const directChatTeamSettings = refreshData.team?.settings;
17672
17775
  const directChatTz = (() => {
17673
17776
  const tz = directChatTeamSettings?.["timezone"];
@@ -17693,7 +17796,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17693
17796
  // ~/.augmented/<codeName>/.current-turn-initiator.json. Note getAgentDir
17694
17797
  // returns the agent root (NOT the /provision subdir `agentDir` points at),
17695
17798
  // so it byte-matches the broker readers' path.
17696
- AGT_TURN_INITIATOR_FILE: join41(
17799
+ AGT_TURN_INITIATOR_FILE: join42(
17697
17800
  frameworkAdapter.getAgentDir(agent.code_name),
17698
17801
  ".current-turn-initiator.json"
17699
17802
  )
@@ -17713,7 +17816,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17713
17816
  log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
17714
17817
  }
17715
17818
  }
17716
- const staleChannelsPath = join41(projectDir, ".mcp-channels.json");
17819
+ const staleChannelsPath = join42(projectDir, ".mcp-channels.json");
17717
17820
  if (existsSync19(staleChannelsPath)) {
17718
17821
  try {
17719
17822
  rmSync8(staleChannelsPath, { force: true });
@@ -17826,7 +17929,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17826
17929
  }
17827
17930
  if (hostFlagStore().getBoolean("connectivity-probe")) {
17828
17931
  try {
17829
- const probeProjectDir = join41(homedir17(), ".augmented", agent.code_name, "project");
17932
+ const probeProjectDir = join42(homedir18(), ".augmented", agent.code_name, "project");
17830
17933
  let probeSet = integrations;
17831
17934
  const fetchQuarantined = async () => {
17832
17935
  const quarantined = await api.post("/host/agent-integrations/quarantined", { agent_id: agent.agent_id });
@@ -17886,7 +17989,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17886
17989
  const forceDue = attemptsLeft > 0;
17887
17990
  let probeRan = false;
17888
17991
  try {
17889
- const probeProjectDir = join41(homedir17(), ".augmented", agent.code_name, "project");
17992
+ const probeProjectDir = join42(homedir18(), ".augmented", agent.code_name, "project");
17890
17993
  probeRan = await runAgentSessionToolBindProbes(agent, integrations, probeProjectDir, { forceDue });
17891
17994
  } catch (err) {
17892
17995
  log(`Session-tool-bind probe failed for '${agent.code_name}': ${err.message}`);
@@ -17963,11 +18066,11 @@ async function processAgent(agent, agentStates, managedToolkits) {
17963
18066
  const intHash = computeIntegrationsHash(integrations);
17964
18067
  const prevIntHash = agentState.knownIntegrationHashes.get(agent.agent_id);
17965
18068
  if (intHash !== prevIntHash) {
17966
- const projectDir = join41(homedir17(), ".augmented", agent.code_name, "project");
17967
- const envIntPath = join41(projectDir, ".env.integrations");
18069
+ const projectDir = join42(homedir18(), ".augmented", agent.code_name, "project");
18070
+ const envIntPath = join42(projectDir, ".env.integrations");
17968
18071
  let preWriteEnv;
17969
18072
  try {
17970
- preWriteEnv = readFileSync32(envIntPath, "utf-8");
18073
+ preWriteEnv = readFileSync33(envIntPath, "utf-8");
17971
18074
  } catch {
17972
18075
  preWriteEnv = void 0;
17973
18076
  }
@@ -17986,9 +18089,9 @@ async function processAgent(agent, agentStates, managedToolkits) {
17986
18089
  }
17987
18090
  if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
17988
18091
  try {
17989
- const projectMcpPath = join41(projectDir, ".mcp.json");
17990
- const postWriteEnv = readFileSync32(envIntPath, "utf-8");
17991
- const mcpContent = readFileSync32(projectMcpPath, "utf-8");
18092
+ const projectMcpPath = join42(projectDir, ".mcp.json");
18093
+ const postWriteEnv = readFileSync33(envIntPath, "utf-8");
18094
+ const mcpContent = readFileSync33(projectMcpPath, "utf-8");
17992
18095
  const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
17993
18096
  const mcpJsonForReap = JSON.parse(mcpContent);
17994
18097
  const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
@@ -18287,16 +18390,16 @@ async function processAgent(agent, agentStates, managedToolkits) {
18287
18390
  }
18288
18391
  try {
18289
18392
  const { readdirSync: readdirSync13, rmSync: rmSync9 } = await import("fs");
18290
- const { homedir: homedir18 } = await import("os");
18393
+ const { homedir: homedir19 } = await import("os");
18291
18394
  const frameworkId2 = frameworkAdapter.id;
18292
18395
  const candidateSkillDirs = [
18293
18396
  // Claude Code — framework runtime tree
18294
- join41(homedir18(), ".augmented", agent.code_name, "skills"),
18397
+ join42(homedir19(), ".augmented", agent.code_name, "skills"),
18295
18398
  // Claude Code — project tree
18296
- join41(homedir18(), ".augmented", agent.code_name, "project", ".claude", "skills"),
18399
+ join42(homedir19(), ".augmented", agent.code_name, "project", ".claude", "skills"),
18297
18400
  // Defensive: legacy provision-side path, not currently an
18298
18401
  // install target but cheap to sweep.
18299
- join41(agentDir, ".claude", "skills")
18402
+ join42(agentDir, ".claude", "skills")
18300
18403
  ];
18301
18404
  const existingDirs = candidateSkillDirs.filter((d) => existsSync19(d));
18302
18405
  const discoveredEntries = /* @__PURE__ */ new Set();
@@ -18339,7 +18442,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
18339
18442
  const sharedSkillsPayload = refreshAny.shared_skills;
18340
18443
  const desiredResolved = globalSkillsPayload !== void 0 || sharedSkillsPayload !== void 0;
18341
18444
  const manifestPath = managedSkillManifestPath(
18342
- join41(homedir17(), ".augmented", agent.code_name)
18445
+ join42(homedir18(), ".augmented", agent.code_name)
18343
18446
  );
18344
18447
  const prevIds = /* @__PURE__ */ new Set([
18345
18448
  ...agentState.knownGlobalSkillIds.get(agent.agent_id) ?? /* @__PURE__ */ new Set(),
@@ -18359,15 +18462,15 @@ async function processAgent(agent, agentStates, managedToolkits) {
18359
18462
  }
18360
18463
  if (plan.removes.length) {
18361
18464
  const globalSkillDirs = [
18362
- join41(homedir17(), ".augmented", agent.code_name, "skills"),
18363
- join41(homedir17(), ".augmented", agent.code_name, "project", ".claude", "skills"),
18364
- join41(agentDir, ".claude", "skills")
18465
+ join42(homedir18(), ".augmented", agent.code_name, "skills"),
18466
+ join42(homedir18(), ".augmented", agent.code_name, "project", ".claude", "skills"),
18467
+ join42(agentDir, ".claude", "skills")
18365
18468
  ];
18366
18469
  for (const id of plan.removes) {
18367
18470
  let prunedAny = false;
18368
18471
  for (const dir of globalSkillDirs) {
18369
- const p = join41(dir, id);
18370
- if (existsSync19(p) && existsSync19(join41(p, "SKILL.md"))) {
18472
+ const p = join42(dir, id);
18473
+ if (existsSync19(p) && existsSync19(join42(p, "SKILL.md"))) {
18371
18474
  rmSync8(p, { recursive: true, force: true });
18372
18475
  prunedAny = true;
18373
18476
  }
@@ -18623,8 +18726,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
18623
18726
  const sess = getSessionState(agent.code_name);
18624
18727
  let mcpJsonParsed = null;
18625
18728
  try {
18626
- const mcpPath = join41(getProjectDir(agent.code_name), ".mcp.json");
18627
- mcpJsonParsed = JSON.parse(readFileSync32(mcpPath, "utf-8"));
18729
+ const mcpPath = join42(getProjectDir(agent.code_name), ".mcp.json");
18730
+ mcpJsonParsed = JSON.parse(readFileSync33(mcpPath, "utf-8"));
18628
18731
  } catch {
18629
18732
  }
18630
18733
  const computerUseIsolated = isolationMode(agent.code_name) === "docker";
@@ -19116,7 +19219,7 @@ Retried to the limit after repeated stalls \u2014 needs a look.`).catch(() => {
19116
19219
  if (trackedFiles.length > 0 && existsSync19(agentDir)) {
19117
19220
  const hashes = /* @__PURE__ */ new Map();
19118
19221
  for (const file of trackedFiles) {
19119
- const h = hashFile(join41(agentDir, file));
19222
+ const h = hashFile(join42(agentDir, file));
19120
19223
  if (h) hashes.set(file, h);
19121
19224
  }
19122
19225
  agentState.writtenHashes.set(agent.agent_id, hashes);
@@ -19131,7 +19234,7 @@ Retried to the limit after repeated stalls \u2014 needs a look.`).catch(() => {
19131
19234
  refreshData.agent.onboarding_state
19132
19235
  );
19133
19236
  const obStep = obState.step;
19134
- const markerPath = join41(homedir17(), ".augmented", agent.code_name, "onboarding-drive.json");
19237
+ const markerPath = join42(homedir18(), ".augmented", agent.code_name, "onboarding-drive.json");
19135
19238
  const marker = readOnboardingDriveMarker(markerPath);
19136
19239
  const obContactRaw = refreshData.agent.manager_last_contacted_at;
19137
19240
  const obContact = typeof obContactRaw === "string" && obContactRaw ? obContactRaw : null;
@@ -19246,7 +19349,7 @@ async function ensureOpencodeRuntime(agent, refreshData, agentTimezone) {
19246
19349
  }
19247
19350
  stopOpencodeSlackIngest(codeName, log);
19248
19351
  stopOpencodeTelegramIngest(codeName, log);
19249
- const opencodeProjectDir = join41(getFramework("opencode").getAgentDir(codeName), "provision");
19352
+ const opencodeProjectDir = join42(getFramework("opencode").getAgentDir(codeName), "provision");
19250
19353
  const serveEnv = {
19251
19354
  AGT_HOST: requireHost(),
19252
19355
  AGT_API_KEY: getApiKey() ?? void 0,
@@ -19306,8 +19409,8 @@ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refres
19306
19409
  });
19307
19410
  }
19308
19411
  const projectDir = getProjectDir(codeName);
19309
- const mcpConfigPath = join41(projectDir, ".mcp.json");
19310
- const claudeMdPath = join41(projectDir, "CLAUDE.md");
19412
+ const mcpConfigPath = join42(projectDir, ".mcp.json");
19413
+ const claudeMdPath = join42(projectDir, "CLAUDE.md");
19311
19414
  if (restartBreaker.isTripped(codeName)) {
19312
19415
  const trip = restartBreaker.getTrip(codeName);
19313
19416
  return {
@@ -19544,7 +19647,7 @@ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refres
19544
19647
  const overdueMin = rolloverCurrent ? minutesSinceLocalMidnight(/* @__PURE__ */ new Date(), agentTimezone) : 0;
19545
19648
  const rolloverMayForce = staleForToday && rolloverSessionHealthy && rolloverCurrent !== null && overdueMin >= DAY_ROLLOVER_FORCE_GRACE_MIN;
19546
19649
  const rolloverInboundAgeSec = rolloverMayForce ? await channelInboundActivityAgeSecondsFor(codeName) : null;
19547
- const rolloverDecision = decideDayRolloverAction({
19650
+ const rolloverInputs = {
19548
19651
  staleForToday,
19549
19652
  sessionHealthy: rolloverSessionHealthy,
19550
19653
  hasCurrent: rolloverCurrent !== null,
@@ -19555,7 +19658,11 @@ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refres
19555
19658
  inboundGraceSec: DAY_ROLLOVER_INBOUND_GRACE_SEC,
19556
19659
  inboundDeferredMin: inboundHeldMinutesFor(codeName),
19557
19660
  inboundDeferMaxMin: DAY_ROLLOVER_INBOUND_DEFER_MAX_MIN
19558
- });
19661
+ };
19662
+ let rolloverDecision = decideDayRolloverAction(rolloverInputs);
19663
+ if (rolloverDecision === "force-reset" && !deviceStateAllowsRollover(codeName, "force-reset")) {
19664
+ rolloverDecision = decideDayRolloverAction({ ...rolloverInputs, deviceStateReady: false });
19665
+ }
19559
19666
  if (rolloverDecision === "defer-idle" && rolloverCurrent) {
19560
19667
  if (!pendingDayRolloverReset.has(codeName)) {
19561
19668
  pendingDayRolloverReset.add(codeName);
@@ -19582,6 +19689,8 @@ async function ensurePersistentSessionUnchecked(agent, tasks, boardItems, refres
19582
19689
  );
19583
19690
  }
19584
19691
  dayRolloverDeferred = true;
19692
+ } else if (rolloverDecision === "defer-device-state" && rolloverCurrent) {
19693
+ dayRolloverDeferred = true;
19585
19694
  } else if (rolloverDecision === "busy-wait" && rolloverCurrent) {
19586
19695
  log(
19587
19696
  `[persistent-session] Day rollover for '${codeName}' deferred \u2014 agent still active on session ${rolloverCurrent.sessionId} (${overdueMin}m past boundary, will force at ${DAY_ROLLOVER_FORCE_GRACE_MIN}m)`
@@ -20653,7 +20762,7 @@ async function processDirectChatMessage(agent, msg) {
20653
20762
  const useDoorbell = hostFlagStore().getBoolean("direct-chat-doorbell") || isolationMode(agent.codeName) === "docker";
20654
20763
  if (useDoorbell) {
20655
20764
  try {
20656
- const doorbell = directChatDoorbellPath(agent.agentId, homedir17());
20765
+ const doorbell = directChatDoorbellPath(agent.agentId, homedir18());
20657
20766
  mkdirSync15(dirname11(doorbell), { recursive: true });
20658
20767
  writeFileSync18(doorbell, String(Date.now()));
20659
20768
  log(`[direct-chat] Doorbell rung for '${agent.codeName}' (msg=${msg.id}) \u2014 in-session MCP will pull via the cursor`);
@@ -20782,7 +20891,7 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
20782
20891
  }
20783
20892
  if (run_id) openInjectedRunByCode.set(codeName, run_id);
20784
20893
  try {
20785
- const doorbell = directChatDoorbellPath(agentId, homedir17());
20894
+ const doorbell = directChatDoorbellPath(agentId, homedir18());
20786
20895
  mkdirSync15(dirname11(doorbell), { recursive: true });
20787
20896
  writeFileSync18(doorbell, String(Date.now()));
20788
20897
  } catch (err) {
@@ -21119,17 +21228,17 @@ var lastLocalFileHash = /* @__PURE__ */ new Map();
21119
21228
  var lastMemoriesBody = /* @__PURE__ */ new Map();
21120
21229
  var memoryManifests = /* @__PURE__ */ new Map();
21121
21230
  function memoryRetirementDir(configDir, codeName) {
21122
- return join41(configDir, "_memory-retirement", codeName);
21231
+ return join42(configDir, "_memory-retirement", codeName);
21123
21232
  }
21124
21233
  function memoryManifestPath(configDir, codeName) {
21125
- return join41(memoryRetirementDir(configDir, codeName), "manifest.json");
21234
+ return join42(memoryRetirementDir(configDir, codeName), "manifest.json");
21126
21235
  }
21127
21236
  function loadMemoryManifest(agentId, configDir, codeName) {
21128
21237
  const cached = memoryManifests.get(agentId);
21129
21238
  if (cached) return cached;
21130
21239
  let manifest = {};
21131
21240
  try {
21132
- const raw = readFileSync32(memoryManifestPath(configDir, codeName), "utf-8");
21241
+ const raw = readFileSync33(memoryManifestPath(configDir, codeName), "utf-8");
21133
21242
  const parsed = JSON.parse(raw);
21134
21243
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
21135
21244
  for (const [name, entry] of Object.entries(parsed)) {
@@ -21157,7 +21266,7 @@ function saveMemoryManifest(agentId, configDir, codeName) {
21157
21266
  }
21158
21267
  }
21159
21268
  function retiredMemoryDir(configDir, codeName) {
21160
- return join41(memoryRetirementDir(configDir, codeName), "retired");
21269
+ return join42(memoryRetirementDir(configDir, codeName), "retired");
21161
21270
  }
21162
21271
  var RETIRED_MEMORY_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
21163
21272
  var lastRetirementReport = /* @__PURE__ */ new Map();
@@ -21236,7 +21345,7 @@ function applyMemoryTombstones(opts) {
21236
21345
  log2(`[memory-retire] ${agent.code_name}: KEPT '${tomb.name}' \u2014 no write record, not ours to remove`);
21237
21346
  continue;
21238
21347
  }
21239
- const filePath = join41(memoryDir, entry.file);
21348
+ const filePath = join42(memoryDir, entry.file);
21240
21349
  if (!existsSync19(filePath)) {
21241
21350
  outcomes.already_gone++;
21242
21351
  delete manifest[tomb.name];
@@ -21244,7 +21353,7 @@ function applyMemoryTombstones(opts) {
21244
21353
  continue;
21245
21354
  }
21246
21355
  try {
21247
- const actual = createHash20("sha256").update(readFileSync32(filePath)).digest("hex");
21356
+ const actual = createHash20("sha256").update(readFileSync33(filePath)).digest("hex");
21248
21357
  if (actual !== entry.sha) {
21249
21358
  outcomes.kept_modified++;
21250
21359
  outcomes.unapplied.push({ name: tomb.name, reason: "kept_modified" });
@@ -21256,9 +21365,9 @@ function applyMemoryTombstones(opts) {
21256
21365
  const destDir = retiredMemoryDir(configDir, agent.code_name);
21257
21366
  mkdirSync15(destDir, { recursive: true });
21258
21367
  const stamp = Date.now();
21259
- let dest = join41(destDir, `${entry.file}.${stamp}.retired`);
21368
+ let dest = join42(destDir, `${entry.file}.${stamp}.retired`);
21260
21369
  for (let n = 1; existsSync19(dest); n++) {
21261
- dest = join41(destDir, `${entry.file}.${stamp}-${n}.retired`);
21370
+ dest = join42(destDir, `${entry.file}.${stamp}-${n}.retired`);
21262
21371
  }
21263
21372
  renameSync11(filePath, dest);
21264
21373
  try {
@@ -21297,9 +21406,9 @@ function reapRetiredMemories(configDir, codeName, log2) {
21297
21406
  try {
21298
21407
  for (const file of readdirSync12(dir)) {
21299
21408
  if (!file.endsWith(".retired")) continue;
21300
- const path = join41(dir, file);
21409
+ const path = join42(dir, file);
21301
21410
  try {
21302
- if (statSync11(path).mtimeMs < cutoff) {
21411
+ if (statSync12(path).mtimeMs < cutoff) {
21303
21412
  unlinkSync6(path);
21304
21413
  reaped++;
21305
21414
  }
@@ -21312,8 +21421,8 @@ function reapRetiredMemories(configDir, codeName, log2) {
21312
21421
  if (reaped > 0) log2(`[memory-retire] ${codeName}: reaped ${reaped} retired memory file(s) past TTL`);
21313
21422
  }
21314
21423
  async function syncMemories(agent, configDir, log2) {
21315
- const projectDir = join41(configDir, agent.code_name, "project");
21316
- const memoryDir = join41(projectDir, "memory");
21424
+ const projectDir = join42(configDir, agent.code_name, "project");
21425
+ const memoryDir = join42(projectDir, "memory");
21317
21426
  const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
21318
21427
  if (isFreshSync) {
21319
21428
  log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
@@ -21344,7 +21453,7 @@ async function syncMemories(agent, configDir, log2) {
21344
21453
  for (const file of readdirSync12(memoryDir)) {
21345
21454
  if (!file.endsWith(".md")) continue;
21346
21455
  try {
21347
- const raw = readFileSync32(join41(memoryDir, file), "utf-8");
21456
+ const raw = readFileSync33(join42(memoryDir, file), "utf-8");
21348
21457
  const fileHash = createHash20("sha256").update(raw).digest("hex").slice(0, 16);
21349
21458
  currentHashes.set(file, fileHash);
21350
21459
  if (prevHashes.get(file) === fileHash) continue;
@@ -21369,7 +21478,7 @@ async function syncMemories(agent, configDir, log2) {
21369
21478
  } catch (err) {
21370
21479
  for (const mem of changedMemories) {
21371
21480
  for (const [file] of currentHashes) {
21372
- const parsed = parseMemoryFile(readFileSync32(join41(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
21481
+ const parsed = parseMemoryFile(readFileSync33(join42(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
21373
21482
  if (parsed?.name === mem.name) currentHashes.delete(file);
21374
21483
  }
21375
21484
  }
@@ -21450,7 +21559,7 @@ async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
21450
21559
  // Per-agent, not host-wide: memories are agent-private, so a shared
21451
21560
  // store would buy almost no dedupe while exposing one agent's content
21452
21561
  // to every other agent on the host. See memory-cache.ts's header.
21453
- cacheDir: join41(configDir, agent.code_name, "_memory_bodies"),
21562
+ cacheDir: join42(configDir, agent.code_name, "_memory_bodies"),
21454
21563
  fetchContents: async (hashes) => {
21455
21564
  const res = await api.post(
21456
21565
  "/host/memories/contents",
@@ -21488,7 +21597,7 @@ async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
21488
21597
  const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
21489
21598
  const slug = rawSlug || `memory-${i}`;
21490
21599
  const fileName = `${slug}.md`;
21491
- const filePath = join41(memoryDir, fileName);
21600
+ const filePath = join42(memoryDir, fileName);
21492
21601
  const desired = `---
21493
21602
  name: ${JSON.stringify(mem.name)}
21494
21603
  type: ${mem.type}
@@ -21508,7 +21617,7 @@ ${mem.content}
21508
21617
  if (existsSync19(filePath)) {
21509
21618
  let existing = "";
21510
21619
  try {
21511
- existing = readFileSync32(filePath, "utf-8");
21620
+ existing = readFileSync33(filePath, "utf-8");
21512
21621
  } catch {
21513
21622
  }
21514
21623
  if (existing === desired) {
@@ -21874,7 +21983,7 @@ function startManager(opts) {
21874
21983
  try {
21875
21984
  const stateFile = getStateFile();
21876
21985
  if (existsSync19(stateFile)) {
21877
- const raw = readFileSync32(stateFile, "utf-8");
21986
+ const raw = readFileSync33(stateFile, "utf-8");
21878
21987
  const parsed = JSON.parse(raw);
21879
21988
  if (Array.isArray(parsed.agents)) {
21880
21989
  state8.agents = parsed.agents;
@@ -21901,7 +22010,7 @@ function startManager(opts) {
21901
22010
  log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
21902
22011
  }
21903
22012
  log(
21904
- `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join41(homedir17(), ".augmented", "manager.log")}`
22013
+ `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join42(homedir18(), ".augmented", "manager.log")}`
21905
22014
  );
21906
22015
  deployMcpAssets();
21907
22016
  reapOrphanChannelMcps({ log });
@@ -21930,7 +22039,7 @@ async function reapOrphanedClaudePids() {
21930
22039
  const looksLikeClaude = (pid) => {
21931
22040
  if (process.platform !== "linux") return true;
21932
22041
  try {
21933
- const comm = readFileSync32(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
22042
+ const comm = readFileSync33(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
21934
22043
  return comm.includes("claude");
21935
22044
  } catch {
21936
22045
  return false;
@@ -22027,14 +22136,14 @@ function restartRunningChannelMcps(basenames) {
22027
22136
  }
22028
22137
  }
22029
22138
  function deployMcpAssets() {
22030
- const targetDir = join41(homedir17(), ".augmented", "_mcp");
22139
+ const targetDir = join42(homedir18(), ".augmented", "_mcp");
22031
22140
  mkdirSync15(targetDir, { recursive: true });
22032
22141
  const moduleDir = dirname11(fileURLToPath2(import.meta.url));
22033
22142
  let mcpSourceDir = "";
22034
22143
  let dir = moduleDir;
22035
22144
  for (let i = 0; i < 6; i++) {
22036
- const candidate = join41(dir, "dist", "mcp");
22037
- if (existsSync19(join41(candidate, "index.js"))) {
22145
+ const candidate = join42(dir, "dist", "mcp");
22146
+ if (existsSync19(join42(candidate, "index.js"))) {
22038
22147
  mcpSourceDir = candidate;
22039
22148
  break;
22040
22149
  }
@@ -22052,7 +22161,7 @@ function deployMcpAssets() {
22052
22161
  const fileHash = (p) => {
22053
22162
  try {
22054
22163
  if (!existsSync19(p)) return null;
22055
- return createHash20("sha256").update(readFileSync32(p)).digest("hex");
22164
+ return createHash20("sha256").update(readFileSync33(p)).digest("hex");
22056
22165
  } catch {
22057
22166
  return null;
22058
22167
  }
@@ -22134,8 +22243,8 @@ function deployMcpAssets() {
22134
22243
  // natural session restart.
22135
22244
  "computer-use-proxy.js"
22136
22245
  ]) {
22137
- const src = join41(mcpSourceDir, file);
22138
- const dst = join41(targetDir, file);
22246
+ const src = join42(mcpSourceDir, file);
22247
+ const dst = join42(targetDir, file);
22139
22248
  if (!existsSync19(src)) continue;
22140
22249
  attemptedFiles.push(file);
22141
22250
  const before = fileHash(dst);
@@ -22161,16 +22270,16 @@ function deployMcpAssets() {
22161
22270
  log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
22162
22271
  restartRunningChannelMcps(changedBasenames);
22163
22272
  }
22164
- const localMcpPath = join41(targetDir, "index.js");
22273
+ const localMcpPath = join42(targetDir, "index.js");
22165
22274
  try {
22166
- const agentsDir = join41(homedir17(), ".augmented", "agents");
22275
+ const agentsDir = join42(homedir18(), ".augmented", "agents");
22167
22276
  if (existsSync19(agentsDir)) {
22168
22277
  for (const entry of readdirSync12(agentsDir, { withFileTypes: true })) {
22169
22278
  if (!entry.isDirectory()) continue;
22170
22279
  for (const subdir of ["provision", "project"]) {
22171
- const mcpJsonPath = join41(agentsDir, entry.name, subdir, ".mcp.json");
22280
+ const mcpJsonPath = join42(agentsDir, entry.name, subdir, ".mcp.json");
22172
22281
  try {
22173
- const raw = readFileSync32(mcpJsonPath, "utf-8");
22282
+ const raw = readFileSync33(mcpJsonPath, "utf-8");
22174
22283
  if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
22175
22284
  const mcpConfig = JSON.parse(raw);
22176
22285
  const augServer = mcpConfig.mcpServers?.["augmented"];