@integrity-labs/agt-cli 0.16.1 → 0.16.2

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-MEJGM5RV.js";
26
26
  import {
27
27
  findTaskByTemplate,
28
28
  getProjectDir,
@@ -33,19 +33,21 @@ 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";
@@ -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.2" : "dev";
1480
1488
  function resolveBrewPath(execFileSync2) {
1481
1489
  try {
1482
1490
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -2353,7 +2361,7 @@ async function pollCycle() {
2353
2361
  }
2354
2362
  try {
2355
2363
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
2356
- const { collectDiagnostics } = await import("../persistent-session-RZWMTEZY.js");
2364
+ const { collectDiagnostics } = await import("../persistent-session-YEUFJMWF.js");
2357
2365
  const diagCodeNames = [...persistentSessionAgents];
2358
2366
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
2359
2367
  let tailscaleHostname;
@@ -3827,6 +3835,24 @@ async function finishRun(runId, outcome, options = {}) {
3827
3835
  log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
3828
3836
  }
3829
3837
  }
3838
+ var MAX_PRIOR_RUNS = 5;
3839
+ async function fetchPriorScheduledRuns(agentId, taskId) {
3840
+ try {
3841
+ const data = await api.post("/host/scheduled-tasks/recent-outputs", {
3842
+ agent_id: agentId,
3843
+ task_id: taskId,
3844
+ since_hours: 24,
3845
+ limit: MAX_PRIOR_RUNS
3846
+ });
3847
+ const rows = Array.isArray(data?.runs) ? data.runs.slice(0, MAX_PRIOR_RUNS) : [];
3848
+ return rows.filter((r) => typeof r.output_text === "string" && r.output_text.length > 0).map((r) => ({ startedAt: r.started_at, output: r.output_text }));
3849
+ } catch (err) {
3850
+ const errText = err instanceof Error ? err.message : String(err);
3851
+ const errId = createHash("sha256").update(errText).digest("hex").slice(0, 12);
3852
+ log(`[runs] prior-runs lookup failed for task_id=${taskId} error_id=${errId}`);
3853
+ return [];
3854
+ }
3855
+ }
3830
3856
  async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
3831
3857
  const projectDir = getProjectDir(codeName);
3832
3858
  const mcpConfigPath = join3(projectDir, ".mcp.json");
@@ -3834,7 +3860,8 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
3834
3860
  let kanbanItemId = null;
3835
3861
  let taskResult;
3836
3862
  sanitizeMcpJson(mcpConfigPath, requireHost());
3837
- prompt = wrapScheduledTaskPrompt(prompt);
3863
+ const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
3864
+ prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
3838
3865
  try {
3839
3866
  const claudeMdPath = join3(projectDir, "CLAUDE.md");
3840
3867
  const serverNames = [];
@@ -4129,7 +4156,15 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
4129
4156
  }
4130
4157
  if (!isSessionHealthy(codeName)) {
4131
4158
  if (persistentSessionAgents.has(codeName)) {
4132
- log(`[persistent-session] Session for '${codeName}' is unhealthy, will restart`);
4159
+ const ctx = getLastFailureContext(codeName);
4160
+ const recovery = prepareForRespawn(codeName);
4161
+ const tailSummary = !ctx.tail ? "" : KNOWN_SAFE_TAIL_SIGNATURES.has(ctx.signature) ? `; last pane output (${PANE_TAIL_PREVIEW_LINES} of ~20 lines):
4162
+ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash("sha256").update(ctx.tail).digest("hex").slice(0, 12)} (raw at ~/.augmented/${codeName}/pane.log)`;
4163
+ const sigSummary = ctx.signature !== "unknown" ? `; signature=${ctx.signature}` : "";
4164
+ const recoverySummary = recovery ? `; recovery=${recovery}` : "";
4165
+ log(
4166
+ `[persistent-session] Session for '${codeName}' is unhealthy (restart #${ctx.restartCount}${sigSummary}${recoverySummary}), will restart${tailSummary}`
4167
+ );
4133
4168
  }
4134
4169
  try {
4135
4170
  provisionStopHook(codeName);
@@ -4354,6 +4389,7 @@ function ensureRealtimeAssignStarted(agentStates) {
4354
4389
  hostId: exchange.hostId,
4355
4390
  onAssign: (payload) => {
4356
4391
  log(`[realtime] Agent ${payload.agent_id} assigned \u2014 will pick up next cycle`);
4392
+ markAgentForFreshMemorySync(payload.agent_id);
4357
4393
  },
4358
4394
  onUnassign: (payload) => {
4359
4395
  log(`[realtime] Agent ${payload.agent_id} unassigned`);
@@ -5442,7 +5478,7 @@ async function processClaudePairSessions(agents) {
5442
5478
  killPairSession,
5443
5479
  pairTmuxSession,
5444
5480
  finalizeClaudePairOnboarding
5445
- } = await import("../claude-pair-runtime-FEUHTZXZ.js");
5481
+ } = await import("../claude-pair-runtime-Q7PNH3ZK.js");
5446
5482
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
5447
5483
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
5448
5484
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -5687,6 +5723,13 @@ function generateArtifacts(agent, refreshData, adapter) {
5687
5723
  var memoryFileHashes = /* @__PURE__ */ new Map();
5688
5724
  var lastDownloadHash = /* @__PURE__ */ new Map();
5689
5725
  var lastLocalFileHash = /* @__PURE__ */ new Map();
5726
+ var pendingFreshMemorySync = /* @__PURE__ */ new Set();
5727
+ function markAgentForFreshMemorySync(agentId) {
5728
+ pendingFreshMemorySync.add(agentId);
5729
+ memoryFileHashes.delete(agentId);
5730
+ lastDownloadHash.delete(agentId);
5731
+ lastLocalFileHash.delete(agentId);
5732
+ }
5690
5733
  function parseMemoryFile(raw, fallbackName) {
5691
5734
  const trimmed = raw.trim();
5692
5735
  if (!trimmed) return null;
@@ -5713,6 +5756,16 @@ function parseMemoryFile(raw, fallbackName) {
5713
5756
  async function syncMemories(agent, configDir, log2) {
5714
5757
  const projectDir = join3(configDir, agent.code_name, "project");
5715
5758
  const memoryDir = join3(projectDir, "memory");
5759
+ const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
5760
+ if (isFreshSync) {
5761
+ log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
5762
+ const ok = await downloadMemories(agent, memoryDir, log2, { force: true });
5763
+ if (!ok) {
5764
+ log2(`[memory-sync] Fresh-sync download failed for '${agent.code_name}' \u2014 skipping upload, will retry next tick`);
5765
+ return;
5766
+ }
5767
+ pendingFreshMemorySync.delete(agent.agent_id);
5768
+ }
5716
5769
  if (existsSync2(memoryDir)) {
5717
5770
  const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
5718
5771
  const currentHashes = /* @__PURE__ */ new Map();
@@ -5753,6 +5806,11 @@ async function syncMemories(agent, configDir, log2) {
5753
5806
  }
5754
5807
  }
5755
5808
  }
5809
+ if (!isFreshSync) {
5810
+ await downloadMemories(agent, memoryDir, log2, { force: false });
5811
+ }
5812
+ }
5813
+ async function downloadMemories(agent, memoryDir, log2, { force }) {
5756
5814
  const localFiles = existsSync2(memoryDir) ? readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
5757
5815
  const localListHash = createHash("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
5758
5816
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
@@ -5762,20 +5820,21 @@ async function syncMemories(agent, configDir, log2) {
5762
5820
  agent_id: agent.agent_id
5763
5821
  });
5764
5822
  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;
5823
+ if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {
5824
+ return true;
5767
5825
  }
5768
5826
  lastDownloadHash.set(agent.agent_id, responseHash);
5769
5827
  lastLocalFileHash.set(agent.agent_id, localListHash);
5770
5828
  if (dbMemories.memories?.length) {
5771
5829
  mkdirSync2(memoryDir, { recursive: true });
5772
- const existingFileSet = new Set(localFiles.map((f) => f.replace(/\.md$/, "").toLowerCase()));
5773
5830
  let written = 0;
5774
- for (const mem of dbMemories.memories) {
5831
+ let overwritten = 0;
5832
+ for (let i = 0; i < dbMemories.memories.length; i++) {
5833
+ const mem = dbMemories.memories[i];
5775
5834
  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 = `---
5835
+ const slug = rawSlug || `memory-${i}`;
5836
+ const filePath = join3(memoryDir, `${slug}.md`);
5837
+ const desired = `---
5779
5838
  name: ${JSON.stringify(mem.name)}
5780
5839
  type: ${mem.type}
5781
5840
  description: ${JSON.stringify(mem.content.slice(0, 200))}
@@ -5783,17 +5842,30 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
5783
5842
 
5784
5843
  ${mem.content}
5785
5844
  `;
5786
- writeFileSync2(join3(memoryDir, `${slug}.md`), fileContent);
5787
- written++;
5845
+ if (existsSync2(filePath)) {
5846
+ let existing = "";
5847
+ try {
5848
+ existing = readFileSync2(filePath, "utf-8");
5849
+ } catch {
5850
+ }
5851
+ if (existing === desired) continue;
5852
+ writeFileSync2(filePath, desired);
5853
+ overwritten++;
5854
+ } else {
5855
+ writeFileSync2(filePath, desired);
5856
+ written++;
5857
+ }
5788
5858
  }
5789
- if (written > 0) {
5859
+ if (written > 0 || overwritten > 0) {
5790
5860
  const updatedFiles = readdirSync2(memoryDir).filter((f) => f.endsWith(".md")).sort();
5791
5861
  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}'`);
5862
+ log2(`Memory download for '${agent.code_name}': wrote ${written} new, overwrote ${overwritten} stale`);
5793
5863
  }
5794
5864
  }
5865
+ return true;
5795
5866
  } catch (err) {
5796
5867
  log2(`Memory download failed for '${agent.code_name}': ${err.message}`);
5868
+ return false;
5797
5869
  }
5798
5870
  }
5799
5871
  async function cleanupAgentFiles(codeName, agentDir) {
@@ -6127,6 +6199,7 @@ process.on("disconnect", () => {
6127
6199
  });
6128
6200
  export {
6129
6201
  ChildProcessError,
6202
+ markAgentForFreshMemorySync,
6130
6203
  startManager,
6131
6204
  stopManager
6132
6205
  };