@integrity-labs/agt-cli 0.10.5 → 0.10.7

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.
@@ -10,7 +10,7 @@ import {
10
10
  provisionStopHook,
11
11
  requireHost,
12
12
  resolveChannels
13
- } from "../chunk-R2DDHROT.js";
13
+ } from "../chunk-VDUA5FEW.js";
14
14
  import {
15
15
  findTaskByTemplate,
16
16
  getProjectDir,
@@ -683,6 +683,9 @@ function clearAgentCaches(agentId, codeName) {
683
683
  lastHarvestAt.delete(codeName);
684
684
  claudeSchedulerStates.delete(codeName);
685
685
  claudeTaskConcurrency.delete(codeName);
686
+ memoryFileHashes.delete(agentId);
687
+ lastDownloadHash.delete(agentId);
688
+ lastLocalFileHash.delete(agentId);
686
689
  for (const key of knownChannelConfigHashes.keys()) {
687
690
  if (key.startsWith(`${agentId}:`)) knownChannelConfigHashes.delete(key);
688
691
  }
@@ -1703,13 +1706,20 @@ async function processAgent(agent, agentStates) {
1703
1706
  if (!pluginName) continue;
1704
1707
  const entry = refreshData.channel_configs[channelId];
1705
1708
  if (!entry || entry.status !== "active" && entry.status !== "pending") continue;
1706
- const pluginDir = join(homedir(), ".claude", "plugins", pluginName);
1707
- if (existsSync(pluginDir)) continue;
1709
+ try {
1710
+ const installedPath = join(homedir(), ".claude", "plugins", "installed_plugins.json");
1711
+ if (existsSync(installedPath)) {
1712
+ const installed = JSON.parse(readFileSync(installedPath, "utf-8"));
1713
+ const pluginKeys = Object.keys(installed.plugins ?? {});
1714
+ if (pluginKeys.some((k) => k.startsWith(`${pluginName}@`))) continue;
1715
+ }
1716
+ } catch {
1717
+ }
1708
1718
  try {
1709
1719
  const { execFileSync: efs } = await import("child_process");
1710
1720
  const claudePath = efs("which", ["claude"], { timeout: 5e3 }).toString().trim();
1711
1721
  if (claudePath) {
1712
- efs(claudePath, ["plugin", "add", pluginName], {
1722
+ efs(claudePath, ["plugin", "install", pluginName], {
1713
1723
  timeout: 3e4,
1714
1724
  stdio: "pipe"
1715
1725
  });
@@ -2280,6 +2290,13 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
2280
2290
  }
2281
2291
  }
2282
2292
  }
2293
+ if (frameworkId === "claude-code" && agent.status === "active") {
2294
+ try {
2295
+ await syncMemories(agent, config.configDir, log);
2296
+ } catch (err) {
2297
+ log(`Memory sync failed for '${agent.code_name}': ${err.message}`);
2298
+ }
2299
+ }
2283
2300
  agentStates.push({
2284
2301
  agentId: agent.agent_id,
2285
2302
  codeName: agent.code_name,
@@ -3813,11 +3830,123 @@ function generateArtifacts(agent, refreshData, adapter) {
3813
3830
  timezone: agentTimezone,
3814
3831
  reportsTo,
3815
3832
  personalitySeed,
3816
- knowledge: (refreshData.knowledge ?? []).filter((k) => !!k.content)
3833
+ knowledge: (refreshData.knowledge ?? []).filter((k) => !!k.content),
3834
+ teamMembers: refreshData.team_members ?? void 0,
3835
+ people: refreshData.people ?? void 0
3817
3836
  };
3818
3837
  const provisionOutput = provision(provisionInput, adapter.id);
3819
3838
  return provisionOutput.artifacts;
3820
3839
  }
3840
+ var memoryFileHashes = /* @__PURE__ */ new Map();
3841
+ var lastDownloadHash = /* @__PURE__ */ new Map();
3842
+ var lastLocalFileHash = /* @__PURE__ */ new Map();
3843
+ function parseMemoryFile(raw, fallbackName) {
3844
+ const trimmed = raw.trim();
3845
+ if (!trimmed) return null;
3846
+ const fmMatch = trimmed.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
3847
+ if (fmMatch) {
3848
+ const frontmatter = fmMatch[1] ?? "";
3849
+ const body = (fmMatch[2] ?? "").trim();
3850
+ if (!body) return null;
3851
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
3852
+ const typeMatch = frontmatter.match(/^type:\s*(.+)$/m);
3853
+ const name = nameMatch?.[1]?.trim().replace(/^["']|["']$/g, "") ?? fallbackName;
3854
+ const rawType = typeMatch?.[1]?.trim().replace(/^["']|["']$/g, "") ?? "user";
3855
+ const typeMap = { user: "user", feedback: "feedback", project: "project", reference: "reference", daily: "daily" };
3856
+ const type = typeMap[rawType] ?? "user";
3857
+ return { name, content: body, type };
3858
+ }
3859
+ const isDaily = /^\d{4}-\d{2}-\d{2}$/.test(fallbackName);
3860
+ return {
3861
+ name: fallbackName,
3862
+ content: trimmed,
3863
+ type: isDaily ? "daily" : "project"
3864
+ };
3865
+ }
3866
+ async function syncMemories(agent, configDir, log2) {
3867
+ const projectDir = join(configDir, agent.code_name, "project");
3868
+ const memoryDir = join(projectDir, "memory");
3869
+ if (existsSync(memoryDir)) {
3870
+ const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
3871
+ const currentHashes = /* @__PURE__ */ new Map();
3872
+ const changedMemories = [];
3873
+ for (const file of readdirSync(memoryDir)) {
3874
+ if (!file.endsWith(".md")) continue;
3875
+ try {
3876
+ const raw = readFileSync(join(memoryDir, file), "utf-8");
3877
+ const fileHash = createHash("sha256").update(raw).digest("hex").slice(0, 16);
3878
+ currentHashes.set(file, fileHash);
3879
+ if (prevHashes.get(file) === fileHash) continue;
3880
+ const parsed = parseMemoryFile(raw, file.replace(/\.md$/, ""));
3881
+ if (parsed) {
3882
+ if (parsed.type === "daily") {
3883
+ parsed.expires_at = new Date(Date.now() + 48 * 60 * 60 * 1e3).toISOString();
3884
+ }
3885
+ changedMemories.push(parsed);
3886
+ }
3887
+ } catch {
3888
+ }
3889
+ }
3890
+ memoryFileHashes.set(agent.agent_id, currentHashes);
3891
+ if (changedMemories.length > 0) {
3892
+ try {
3893
+ await api.post("/host/sync-memories", {
3894
+ agent_id: agent.agent_id,
3895
+ memories: changedMemories
3896
+ });
3897
+ log2(`Synced ${changedMemories.length} changed memories to DB for '${agent.code_name}'`);
3898
+ } catch (err) {
3899
+ for (const mem of changedMemories) {
3900
+ for (const [file, hash] of currentHashes) {
3901
+ const parsed = parseMemoryFile(readFileSync(join(memoryDir, file), "utf-8"), "");
3902
+ if (parsed?.name === mem.name) currentHashes.delete(file);
3903
+ }
3904
+ }
3905
+ log2(`Memory upload failed for '${agent.code_name}': ${err.message}`);
3906
+ }
3907
+ }
3908
+ }
3909
+ const localFiles = existsSync(memoryDir) ? readdirSync(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
3910
+ const localListHash = createHash("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
3911
+ const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
3912
+ const prevDownload = lastDownloadHash.get(agent.agent_id);
3913
+ if (prevDownload && prevLocalHash === localListHash) return;
3914
+ try {
3915
+ const dbMemories = await api.post("/host/memories", {
3916
+ agent_id: agent.agent_id
3917
+ });
3918
+ const responseHash = createHash("sha256").update(JSON.stringify(dbMemories.memories ?? [])).digest("hex").slice(0, 16);
3919
+ lastDownloadHash.set(agent.agent_id, responseHash);
3920
+ lastLocalFileHash.set(agent.agent_id, localListHash);
3921
+ if (dbMemories.memories?.length) {
3922
+ mkdirSync(memoryDir, { recursive: true });
3923
+ const existingFileSet = new Set(localFiles.map((f) => f.replace(/\.md$/, "").toLowerCase()));
3924
+ let written = 0;
3925
+ for (const mem of dbMemories.memories) {
3926
+ const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
3927
+ const slug = rawSlug || `memory-${written}`;
3928
+ if (existingFileSet.has(slug)) continue;
3929
+ const fileContent = `---
3930
+ name: ${JSON.stringify(mem.name)}
3931
+ type: ${mem.type}
3932
+ description: ${JSON.stringify(mem.content.slice(0, 200))}
3933
+ ---
3934
+
3935
+ ${mem.content}
3936
+ `;
3937
+ writeFileSync(join(memoryDir, `${slug}.md`), fileContent);
3938
+ written++;
3939
+ }
3940
+ if (written > 0) {
3941
+ const updatedFiles = readdirSync(memoryDir).filter((f) => f.endsWith(".md")).sort();
3942
+ lastLocalFileHash.set(agent.agent_id, createHash("sha256").update(updatedFiles.join(",")).digest("hex").slice(0, 16));
3943
+ log2(`Exported ${written} DB memories to local files for '${agent.code_name}'`);
3944
+ }
3945
+ }
3946
+ } catch (err) {
3947
+ log2(`Memory download failed for '${agent.code_name}': ${err.message}`);
3948
+ }
3949
+ }
3821
3950
  async function cleanupAgentFiles(codeName, agentDir) {
3822
3951
  if (existsSync(agentDir)) {
3823
3952
  try {