@integrity-labs/agt-cli 0.16.1 → 0.16.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-RZWMTEZY.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-YEUFJMWF.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  try {
106
106
  await execFileAsync("tmux", [
@@ -357,4 +357,4 @@ export {
357
357
  startClaudePair,
358
358
  submitClaudePairCode
359
359
  };
360
- //# sourceMappingURL=claude-pair-runtime-FEUHTZXZ.js.map
360
+ //# sourceMappingURL=claude-pair-runtime-Q7PNH3ZK.js.map
@@ -22,7 +22,7 @@ import {
22
22
  resolveChannels,
23
23
  resolveDmTarget,
24
24
  wrapScheduledTaskPrompt
25
- } from "../chunk-ITLXAEXI.js";
25
+ } from "../chunk-ZQFCMUNR.js";
26
26
  import {
27
27
  findTaskByTemplate,
28
28
  getProjectDir,
@@ -33,23 +33,25 @@ import {
33
33
  } from "../chunk-M6FSTVGG.js";
34
34
  import {
35
35
  buildAllowedTools,
36
+ getLastFailureContext,
36
37
  getProjectDir as getProjectDir2,
37
38
  injectMessage,
38
39
  isAgentIdle,
39
40
  isSessionHealthy,
40
41
  isStaleForToday,
41
42
  peekCurrentSession,
43
+ prepareForRespawn,
42
44
  resetRestartCount,
43
45
  resolveClaudeBinary,
44
46
  sanitizeMcpJson,
45
47
  startPersistentSession,
46
48
  stopAllSessionsAndWait,
47
49
  stopPersistentSession
48
- } from "../chunk-QYG5LUTP.js";
50
+ } from "../chunk-EG5D3KUV.js";
49
51
 
50
52
  // src/lib/manager-worker.ts
51
53
  import { createHash } from "crypto";
52
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync2, rmSync as rmSync2, readdirSync as readdirSync2, statSync, unlinkSync, copyFileSync } from "fs";
54
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, appendFileSync, mkdirSync as mkdirSync2, chmodSync, existsSync as existsSync2, rmSync as rmSync2, readdirSync as readdirSync2, statSync, unlinkSync, copyFileSync } from "fs";
53
55
  import https from "https";
54
56
  import { execFileSync as syncExecFile } from "child_process";
55
57
  import { join as join3, dirname } from "path";
@@ -1402,6 +1404,12 @@ var lastChannelSweepAt = 0;
1402
1404
  var config = null;
1403
1405
  var running = false;
1404
1406
  var pollTimer = null;
1407
+ var PANE_TAIL_PREVIEW_LINES = 5;
1408
+ function truncateForLog(s) {
1409
+ const lines = s.split("\n").filter((l) => l.length > 0);
1410
+ return lines.slice(-PANE_TAIL_PREVIEW_LINES).map((l) => ` | ${l}`).join("\n");
1411
+ }
1412
+ var KNOWN_SAFE_TAIL_SIGNATURES = /* @__PURE__ */ new Set(["session_id_in_use"]);
1405
1413
  var knownVersions = /* @__PURE__ */ new Map();
1406
1414
  var knownStatuses = /* @__PURE__ */ new Map();
1407
1415
  var knownChannels = /* @__PURE__ */ new Map();
@@ -1476,7 +1484,7 @@ function clearAgentCaches(agentId, codeName) {
1476
1484
  var cachedFrameworkVersion = null;
1477
1485
  var lastVersionCheckAt = 0;
1478
1486
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
1479
- var agtCliVersion = true ? "0.16.1" : "dev";
1487
+ var agtCliVersion = true ? "0.16.3" : "dev";
1480
1488
  function resolveBrewPath(execFileSync2) {
1481
1489
  try {
1482
1490
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -1948,6 +1956,7 @@ function send(msg) {
1948
1956
  }
1949
1957
  }
1950
1958
  var managerLogPath = null;
1959
+ var managerLogWritable = true;
1951
1960
  function redactForDiskLog(value) {
1952
1961
  try {
1953
1962
  return value.replace(/\b(Bearer\s+)[A-Za-z0-9._-]+\b/gi, "$1[REDACTED]").replace(/\bxox[baprs]-[A-Za-z0-9-]+\b/g, "[REDACTED-SLACK]").replace(/\btlk_[A-Za-z0-9._-]+\b/g, "[REDACTED-HOST]").replace(/\bsk-ant-[A-Za-z0-9_-]+\b/g, "[REDACTED-ANTHROPIC]").replace(/\b\d{8,12}:[A-Za-z0-9_-]{30,}\b/g, "[REDACTED-TELEGRAM]").replace(
@@ -1961,8 +1970,8 @@ function redactForDiskLog(value) {
1961
1970
  function log(msg) {
1962
1971
  const ts = (/* @__PURE__ */ new Date()).toISOString();
1963
1972
  const safeMsg = redactForDiskLog(msg);
1964
- process.stderr.write(`[manager-worker ${ts}] ${safeMsg}
1965
- `);
1973
+ const line = `[manager-worker ${ts}] ${safeMsg}
1974
+ `;
1966
1975
  if (!managerLogPath) {
1967
1976
  try {
1968
1977
  managerLogPath = join3(homedir3(), ".augmented", "manager.log");
@@ -1973,6 +1982,22 @@ function log(msg) {
1973
1982
  } catch {
1974
1983
  }
1975
1984
  }
1985
+ let appendedToFile = false;
1986
+ if (managerLogPath && managerLogWritable) {
1987
+ try {
1988
+ appendFileSync(managerLogPath, line, { encoding: "utf-8", mode: 384 });
1989
+ appendedToFile = true;
1990
+ } catch (err) {
1991
+ managerLogWritable = false;
1992
+ process.stderr.write(
1993
+ `[manager-worker ${ts}] [log] manager.log append failed; falling back to stderr-only: ${err.message}
1994
+ `
1995
+ );
1996
+ }
1997
+ }
1998
+ if (!appendedToFile || process.stderr.isTTY === true) {
1999
+ process.stderr.write(line);
2000
+ }
1976
2001
  }
1977
2002
  function sha256(content) {
1978
2003
  return createHash("sha256").update(content, "utf8").digest("hex");
@@ -2353,7 +2378,7 @@ async function pollCycle() {
2353
2378
  }
2354
2379
  try {
2355
2380
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
2356
- const { collectDiagnostics } = await import("../persistent-session-RZWMTEZY.js");
2381
+ const { collectDiagnostics } = await import("../persistent-session-YEUFJMWF.js");
2357
2382
  const diagCodeNames = [...persistentSessionAgents];
2358
2383
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
2359
2384
  let tailscaleHostname;
@@ -3827,6 +3852,24 @@ async function finishRun(runId, outcome, options = {}) {
3827
3852
  log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
3828
3853
  }
3829
3854
  }
3855
+ var MAX_PRIOR_RUNS = 5;
3856
+ async function fetchPriorScheduledRuns(agentId, taskId) {
3857
+ try {
3858
+ const data = await api.post("/host/scheduled-tasks/recent-outputs", {
3859
+ agent_id: agentId,
3860
+ task_id: taskId,
3861
+ since_hours: 24,
3862
+ limit: MAX_PRIOR_RUNS
3863
+ });
3864
+ const rows = Array.isArray(data?.runs) ? data.runs.slice(0, MAX_PRIOR_RUNS) : [];
3865
+ return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
3866
+ } catch (err) {
3867
+ const errText = err instanceof Error ? err.message : String(err);
3868
+ const errId = createHash("sha256").update(errText).digest("hex").slice(0, 12);
3869
+ log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
3870
+ return [];
3871
+ }
3872
+ }
3830
3873
  async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
3831
3874
  const projectDir = getProjectDir(codeName);
3832
3875
  const mcpConfigPath = join3(projectDir, ".mcp.json");
@@ -3834,7 +3877,8 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
3834
3877
  let kanbanItemId = null;
3835
3878
  let taskResult;
3836
3879
  sanitizeMcpJson(mcpConfigPath, requireHost());
3837
- prompt = wrapScheduledTaskPrompt(prompt);
3880
+ const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
3881
+ prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
3838
3882
  try {
3839
3883
  const claudeMdPath = join3(projectDir, "CLAUDE.md");
3840
3884
  const serverNames = [];
@@ -4129,7 +4173,15 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
4129
4173
  }
4130
4174
  if (!isSessionHealthy(codeName)) {
4131
4175
  if (persistentSessionAgents.has(codeName)) {
4132
- log(`[persistent-session] Session for '${codeName}' is unhealthy, will restart`);
4176
+ const ctx = getLastFailureContext(codeName);
4177
+ const recovery = prepareForRespawn(codeName);
4178
+ const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
4179
+ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
4180
+ const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
4181
+ const recoverySummary = recovery ? `; recovery=${recovery}` : "";
4182
+ log(
4183
+ `[persistent-session] Session for '${codeName}' is unhealthy (restart #${ctx.restartCount}${sigSummary}${recoverySummary}), will restart${tailSummary}`
4184
+ );
4133
4185
  }
4134
4186
  try {
4135
4187
  provisionStopHook(codeName);
@@ -4354,6 +4406,7 @@ function ensureRealtimeAssignStarted(agentStates) {
4354
4406
  hostId: exchange.hostId,
4355
4407
  onAssign: (payload) => {
4356
4408
  log(`[realtime] Agent ${payload.agent_id} assigned \u2014 will pick up next cycle`);
4409
+ markAgentForFreshMemorySync(payload.agent_id);
4357
4410
  },
4358
4411
  onUnassign: (payload) => {
4359
4412
  log(`[realtime] Agent ${payload.agent_id} unassigned`);
@@ -5442,7 +5495,7 @@ async function processClaudePairSessions(agents) {
5442
5495
  killPairSession,
5443
5496
  pairTmuxSession,
5444
5497
  finalizeClaudePairOnboarding
5445
- } = await import("../claude-pair-runtime-FEUHTZXZ.js");
5498
+ } = await import("../claude-pair-runtime-Q7PNH3ZK.js");
5446
5499
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
5447
5500
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
5448
5501
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -5687,6 +5740,13 @@ function generateArtifacts(agent, refreshData, adapter) {
5687
5740
  var memoryFileHashes = /* @__PURE__ */ new Map();
5688
5741
  var lastDownloadHash = /* @__PURE__ */ new Map();
5689
5742
  var lastLocalFileHash = /* @__PURE__ */ new Map();
5743
+ var pendingFreshMemorySync = /* @__PURE__ */ new Set();
5744
+ function markAgentForFreshMemorySync(agentId) {
5745
+ pendingFreshMemorySync.add(agentId);
5746
+ memoryFileHashes.delete(agentId);
5747
+ lastDownloadHash.delete(agentId);
5748
+ lastLocalFileHash.delete(agentId);
5749
+ }
5690
5750
  function parseMemoryFile(raw, fallbackName) {
5691
5751
  const trimmed = raw.trim();
5692
5752
  if (!trimmed) return null;
@@ -5713,6 +5773,16 @@ function parseMemoryFile(raw, fallbackName) {
5713
5773
  async function syncMemories(agent, configDir, log2) {
5714
5774
  const projectDir = join3(configDir, agent.code_name, "project");
5715
5775
  const memoryDir = join3(projectDir, "memory");
5776
+ const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
5777
+ if (isFreshSync) {
5778
+ log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
5779
+ const ok = await downloadMemories(agent, memoryDir, log2, { force: true });
5780
+ if (!ok) {
5781
+ log2(`[memory-sync] Fresh-sync download failed for '${agent.code_name}' \u2014 skipping upload, will retry next tick`);
5782
+ return;
5783
+ }
5784
+ pendingFreshMemorySync.delete(agent.agent_id);
5785
+ }
5716
5786
  if (existsSync2(memoryDir)) {
5717
5787
  const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
5718
5788
  const currentHashes = /* @__PURE__ */ new Map();
@@ -5753,6 +5823,11 @@ async function syncMemories(agent, configDir, log2) {
5753
5823
  }
5754
5824
  }
5755
5825
  }
5826
+ if (!isFreshSync) {
5827
+ await downloadMemories(agent, memoryDir, log2, { force: false });
5828
+ }
5829
+ }
5830
+ async function downloadMemories(agent, memoryDir, log2, { force }) {
5756
5831
  const localFiles = existsSync2(memoryDir) ? readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
5757
5832
  const localListHash = createHash("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
5758
5833
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
@@ -5762,20 +5837,21 @@ async function syncMemories(agent, configDir, log2) {
5762
5837
  agent_id: agent.agent_id
5763
5838
  });
5764
5839
  const responseHash = createHash("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
5765
- if (prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
5766
- return;
5840
+ if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
5841
+ return true;
5767
5842
  }
5768
5843
  lastDownloadHash.set(agent.agent_id, responseHash);
5769
5844
  lastLocalFileHash.set(agent.agent_id, localListHash);
5770
5845
  if (dbMemories.memories?.length) {
5771
5846
  mkdirSync2(memoryDir, { recursive: true });
5772
- const existingFileSet = new Set(localFiles.map((f) => f.replace(/\.md$/, "").toLowerCase()));
5773
5847
  let written = 0;
5774
- for (const mem of dbMemories.memories) {
5848
+ let overwritten = 0;
5849
+ for (let i = 0; i < dbMemories.memories.length; i++) {
5850
+ const mem = dbMemories.memories[i];
5775
5851
  const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
5776
- const slug = rawSlug || `memory-${written}`;
5777
- if (existingFileSet.has(slug)) continue;
5778
- const fileContent = `---
5852
+ const slug = rawSlug || `memory-${i}`;
5853
+ const filePath = join3(memoryDir, `${slug}.md`);
5854
+ const desired = `---
5779
5855
  name: ${JSON.stringify(mem.name)}
5780
5856
  type: ${mem.type}
5781
5857
  description: ${JSON.stringify(mem.content.slice(0, 200))}
@@ -5783,17 +5859,30 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
5783
5859
 
5784
5860
  ${mem.content}
5785
5861
  `;
5786
- writeFileSync2(join3(memoryDir, `${slug}.md`), fileContent);
5787
- written++;
5862
+ if (existsSync2(filePath)) {
5863
+ let existing = "";
5864
+ try {
5865
+ existing = readFileSync2(filePath, "utf-8");
5866
+ } catch {
5867
+ }
5868
+ if (existing === desired) continue;
5869
+ writeFileSync2(filePath, desired);
5870
+ overwritten++;
5871
+ } else {
5872
+ writeFileSync2(filePath, desired);
5873
+ written++;
5874
+ }
5788
5875
  }
5789
- if (written > 0) {
5876
+ if (written > 0 || overwritten > 0) {
5790
5877
  const updatedFiles = readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort();
5791
5878
  lastLocalFileHash.set(agent.agent_id, createHash("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
5792
- log2(`Exported ${written} DB memories to local files for '${agent.code_name}'`);
5879
+ log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
5793
5880
  }
5794
5881
  }
5882
+ return true;
5795
5883
  } catch (err) {
5796
5884
  log2(`Memory download failed for '${agent.code_name}': ${err.message}`);
5885
+ return false;
5797
5886
  }
5798
5887
  }
5799
5888
  async function cleanupAgentFiles(codeName, agentDir) {
@@ -5963,6 +6052,9 @@ async function stopPolling(opts = {}) {
5963
6052
  }
5964
6053
  function startManager(opts) {
5965
6054
  config = opts;
6055
+ log(
6056
+ `[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join3(homedir3(), ".augmented", "manager.log")}`
6057
+ );
5966
6058
  deployMcpAssets();
5967
6059
  void ensureHostFrameworkBinaries();
5968
6060
  startPolling();
@@ -6127,6 +6219,7 @@ process.on("disconnect", () => {
6127
6219
  });
6128
6220
  export {
6129
6221
  ChildProcessError,
6222
+ markAgentForFreshMemorySync,
6130
6223
  startManager,
6131
6224
  stopManager
6132
6225
  };