@integrity-labs/agt-cli 0.27.66 → 0.27.68

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  claudeModelAlias,
3
3
  isClaudeFastMode
4
- } from "./chunk-PM3CC2SJ.js";
4
+ } from "./chunk-KPD5KJY7.js";
5
5
  import {
6
6
  reapOrphanChannelMcps
7
7
  } from "./chunk-XWVM4KPK.js";
@@ -10,7 +10,7 @@ import {
10
10
  import { spawn, execSync, execFileSync as execFileSync2 } from "child_process";
11
11
  import { join as join2, dirname } from "path";
12
12
  import { homedir as homedir2, platform, userInfo } from "os";
13
- import { existsSync as existsSync2, readFileSync as readFileSync3, readdirSync, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, copyFileSync, rmSync } from "fs";
13
+ import { existsSync as existsSync3, readFileSync as readFileSync4, readdirSync, writeFileSync as writeFileSync3, appendFileSync, mkdirSync as mkdirSync2, chmodSync, copyFileSync, rmSync } from "fs";
14
14
  import { fileURLToPath } from "url";
15
15
 
16
16
  // src/lib/mcp-sanitize.ts
@@ -62,12 +62,84 @@ function buildAllowedTools(mcpServerNames) {
62
62
  return [...mcpPatterns, ...BASE_TOOLS].join(",");
63
63
  }
64
64
 
65
+ // src/lib/mcp-env-probe.ts
66
+ import { existsSync, readFileSync as readFileSync2 } from "fs";
67
+ var LATE_BOUND_VARS = /* @__PURE__ */ new Set(["AGT_RUN_ID"]);
68
+ var TEMPLATE_VAR_RE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
69
+ function collectVarsFromValue(value, into) {
70
+ if (typeof value === "string") {
71
+ for (const m of value.matchAll(TEMPLATE_VAR_RE)) into.add(m[1]);
72
+ } else if (Array.isArray(value)) {
73
+ for (const v of value) collectVarsFromValue(v, into);
74
+ }
75
+ }
76
+ function findMissingSubstitutionVars(mcpConfig, env) {
77
+ const findings = [];
78
+ if (typeof mcpConfig !== "object" || mcpConfig === null) return findings;
79
+ const servers = mcpConfig.mcpServers;
80
+ if (typeof servers !== "object" || servers === null) return findings;
81
+ for (const [server, raw] of Object.entries(servers)) {
82
+ if (typeof raw !== "object" || raw === null) continue;
83
+ const entry = raw;
84
+ const vars = /* @__PURE__ */ new Set();
85
+ collectVarsFromValue(entry["command"], vars);
86
+ collectVarsFromValue(entry["args"], vars);
87
+ collectVarsFromValue(entry["url"], vars);
88
+ for (const block of [entry["env"], entry["headers"]]) {
89
+ if (typeof block !== "object" || block === null) continue;
90
+ for (const v of Object.values(block)) collectVarsFromValue(v, vars);
91
+ }
92
+ for (const varName of vars) {
93
+ if (LATE_BOUND_VARS.has(varName)) continue;
94
+ const value = env[varName];
95
+ if (value === void 0) {
96
+ findings.push({ varName, server, state: "unset" });
97
+ } else if (value.trim() === "") {
98
+ findings.push({ varName, server, state: "empty" });
99
+ }
100
+ }
101
+ }
102
+ return findings;
103
+ }
104
+ function formatMissingVar(f) {
105
+ return `[mcp-env-substitution] missing var=${f.varName} server=${f.server} state=${f.state}`;
106
+ }
107
+ function parseEnvIntegrations(content) {
108
+ const out = {};
109
+ for (const line of content.split("\n")) {
110
+ if (!line || line.startsWith("#") || !line.includes("=")) continue;
111
+ const eqIdx = line.indexOf("=");
112
+ const key = line.slice(0, eqIdx);
113
+ let value = line.slice(eqIdx + 1);
114
+ if (value.length >= 2 && value.startsWith("'") && value.endsWith("'")) {
115
+ value = value.slice(1, -1).replaceAll("'\\''", "'");
116
+ }
117
+ out[key] = value;
118
+ }
119
+ return out;
120
+ }
121
+ function probeMcpEnvSubstitution(args) {
122
+ try {
123
+ const config = JSON.parse(readFileSync2(args.mcpConfigPath, "utf-8"));
124
+ let env = args.baseEnv;
125
+ if (args.envIntegrationsPath && existsSync(args.envIntegrationsPath)) {
126
+ env = {
127
+ ...args.baseEnv,
128
+ ...parseEnvIntegrations(readFileSync2(args.envIntegrationsPath, "utf-8"))
129
+ };
130
+ }
131
+ return findMissingSubstitutionVars(config, env);
132
+ } catch {
133
+ return [];
134
+ }
135
+ }
136
+
65
137
  // src/lib/persistent-session.ts
66
138
  import { randomUUID as randomUUID2 } from "crypto";
67
139
 
68
140
  // src/lib/daily-session.ts
69
141
  import { randomUUID } from "crypto";
70
- import { existsSync, mkdirSync, readFileSync as readFileSync2, renameSync, statSync, writeFileSync as writeFileSync2 } from "fs";
142
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3, renameSync, statSync, writeFileSync as writeFileSync2 } from "fs";
71
143
  import { homedir } from "os";
72
144
  import { join } from "path";
73
145
  var HISTORY_DAYS = 7;
@@ -97,9 +169,9 @@ function todayLocalIso(now = /* @__PURE__ */ new Date(), timezone) {
97
169
  }
98
170
  function readFile(codeName) {
99
171
  const path = dailySessionPath(codeName);
100
- if (!existsSync(path)) return { current: null, history: [] };
172
+ if (!existsSync2(path)) return { current: null, history: [] };
101
173
  try {
102
- const raw = readFileSync2(path, "utf-8");
174
+ const raw = readFileSync3(path, "utf-8");
103
175
  const parsed = JSON.parse(raw);
104
176
  return {
105
177
  current: parsed.current ?? null,
@@ -168,7 +240,7 @@ function sessionFilePath(projectDir, sessionId) {
168
240
  }
169
241
  function isAgentIdle(projectDir, sessionId, idleSeconds = 60, now = /* @__PURE__ */ new Date()) {
170
242
  const path = sessionFilePath(projectDir, sessionId);
171
- if (!existsSync(path)) return true;
243
+ if (!existsSync2(path)) return true;
172
244
  try {
173
245
  const mtimeMs = statSync(path).mtimeMs;
174
246
  return now.getTime() - mtimeMs >= idleSeconds * 1e3;
@@ -212,7 +284,7 @@ function syncClaudeCredsToRoot() {
212
284
  if (platform() !== "linux") return true;
213
285
  if (typeof process.getuid !== "function" || process.getuid() !== 0) return true;
214
286
  for (const filename of [".credentials.json", "credentials.json"]) {
215
- if (existsSync2(join2("/root/.claude", filename))) return true;
287
+ if (existsSync3(join2("/root/.claude", filename))) return true;
216
288
  }
217
289
  let sourcePath = null;
218
290
  try {
@@ -221,7 +293,7 @@ function syncClaudeCredsToRoot() {
221
293
  if (!entry.isDirectory()) continue;
222
294
  for (const filename of [".credentials.json", "credentials.json"]) {
223
295
  const candidate = join2("/home", entry.name, ".claude", filename);
224
- if (existsSync2(candidate)) {
296
+ if (existsSync3(candidate)) {
225
297
  sourcePath = candidate;
226
298
  break outer;
227
299
  }
@@ -234,7 +306,7 @@ function syncClaudeCredsToRoot() {
234
306
  const sourceFilename = sourcePath.endsWith("credentials.json") && !sourcePath.endsWith(".credentials.json") ? "credentials.json" : ".credentials.json";
235
307
  const targetPath = join2(targetDir, sourceFilename);
236
308
  try {
237
- if (!existsSync2(targetDir)) mkdirSync2(targetDir, { recursive: true, mode: 448 });
309
+ if (!existsSync3(targetDir)) mkdirSync2(targetDir, { recursive: true, mode: 448 });
238
310
  copyFileSync(sourcePath, targetPath);
239
311
  chmodSync(targetPath, 384);
240
312
  return true;
@@ -246,13 +318,13 @@ var cachedClaudePath = null;
246
318
  function resolveClaudeBinary() {
247
319
  if (cachedClaudePath) return cachedClaudePath;
248
320
  const override = process.env.CLAUDE_PATH;
249
- if (override && existsSync2(override)) {
321
+ if (override && existsSync3(override)) {
250
322
  cachedClaudePath = override;
251
323
  return override;
252
324
  }
253
325
  try {
254
326
  const out = execSync("which claude 2>/dev/null", { encoding: "utf-8" }).trim();
255
- if (out && existsSync2(out)) {
327
+ if (out && existsSync3(out)) {
256
328
  cachedClaudePath = out;
257
329
  return out;
258
330
  }
@@ -264,7 +336,7 @@ function resolveClaudeBinary() {
264
336
  "/usr/local/bin/claude"
265
337
  ];
266
338
  for (const p of candidates) {
267
- if (existsSync2(p)) {
339
+ if (existsSync3(p)) {
268
340
  cachedClaudePath = p;
269
341
  return p;
270
342
  }
@@ -282,7 +354,7 @@ function writePersistentClaudeWrapper(args) {
282
354
  // --dangerously-skip-permissions on dedicated EC2 hosts.
283
355
  "export IS_SANDBOX=1"
284
356
  ];
285
- if (existsSync2(envIntegrationsPath)) {
357
+ if (existsSync3(envIntegrationsPath)) {
286
358
  wrapperLines.push(
287
359
  "set -a",
288
360
  `source ${JSON.stringify(envIntegrationsPath)}`,
@@ -299,9 +371,9 @@ function writePersistentClaudeWrapper(args) {
299
371
  return wrapperPath;
300
372
  }
301
373
  function collectMcpServerNames(mcpConfigPath) {
302
- if (!existsSync2(mcpConfigPath)) return [];
374
+ if (!existsSync3(mcpConfigPath)) return [];
303
375
  try {
304
- const data = JSON.parse(readFileSync3(mcpConfigPath, "utf-8"));
376
+ const data = JSON.parse(readFileSync4(mcpConfigPath, "utf-8"));
305
377
  const servers = data.mcpServers;
306
378
  return servers ? Object.keys(servers) : [];
307
379
  } catch {
@@ -315,7 +387,7 @@ function getAcpxBin() {
315
387
  let dir = moduleDir;
316
388
  for (let i = 0; i < 6; i++) {
317
389
  const candidate = join2(dir, "node_modules", ".bin", "acpx");
318
- if (existsSync2(candidate)) {
390
+ if (existsSync3(candidate)) {
319
391
  _acpxBin = candidate;
320
392
  return _acpxBin;
321
393
  }
@@ -379,9 +451,9 @@ function setupPaneLog(tmuxSession, codeName, log) {
379
451
  }
380
452
  function readPaneLogTail(codeName, lines = PANE_TAIL_LINES) {
381
453
  const logPath = paneLogPath(codeName);
382
- if (!existsSync2(logPath)) return null;
454
+ if (!existsSync3(logPath)) return null;
383
455
  try {
384
- const raw = readFileSync3(logPath, "utf-8");
456
+ const raw = readFileSync4(logPath, "utf-8");
385
457
  if (!raw) return null;
386
458
  const stripped = raw.replace(/\x1b\[[0-9;?]*[A-Za-z]/g, "");
387
459
  const all = stripped.split("\n").filter((l) => l.length > 0);
@@ -469,7 +541,7 @@ function spawnSession(config, session) {
469
541
  const claudeDir = join2(homedir2(), ".claude");
470
542
  for (const filename of [".credentials.json", "credentials.json"]) {
471
543
  const p = join2(claudeDir, filename);
472
- if (existsSync2(p)) {
544
+ if (existsSync3(p)) {
473
545
  try {
474
546
  rmSync(p, { force: true });
475
547
  log(`[persistent-session] Removed ${p} (api_key mode active \u2014 preventing OAuth fallback)`);
@@ -495,7 +567,7 @@ function spawnSession(config, session) {
495
567
  if (channels.length > 0) args.push("--channels", ...channels);
496
568
  if (devChannels.length > 0) args.push("--dangerously-load-development-channels", ...devChannels);
497
569
  args.push("--mcp-config", mcpConfigPath);
498
- if (existsSync2(claudeMdPath)) args.push("--system-prompt-file", claudeMdPath);
570
+ if (existsSync3(claudeMdPath)) args.push("--system-prompt-file", claudeMdPath);
499
571
  const modelAlias = claudeModelAlias(config.primaryModel);
500
572
  if (modelAlias) args.push("--model", modelAlias);
501
573
  args.push("--allow-dangerously-skip-permissions");
@@ -529,6 +601,16 @@ function spawnSession(config, session) {
529
601
  if (config.runId) {
530
602
  tmuxEnv["AGT_RUN_ID"] = config.runId;
531
603
  }
604
+ for (const f of probeMcpEnvSubstitution({
605
+ mcpConfigPath,
606
+ envIntegrationsPath: join2(projectDir, ".env.integrations"),
607
+ baseEnv: {
608
+ ...tmuxEnv,
609
+ ...claudeAuthMode === "api_key" && config.anthropicApiKey ? { ANTHROPIC_API_KEY: config.anthropicApiKey } : {}
610
+ }
611
+ })) {
612
+ log(`[persistent-session] ${formatMissingVar(f)} agent=${codeName}`);
613
+ }
532
614
  const child = spawn("tmux", [
533
615
  "new-session",
534
616
  "-d",
@@ -1061,7 +1143,7 @@ function writeAcpxConfig(config) {
1061
1143
  if (channels.length > 0) claudeArgs.push("--channels", ...channels);
1062
1144
  if (devChannels.length > 0) claudeArgs.push("--dangerously-load-development-channels", ...devChannels);
1063
1145
  claudeArgs.push("--mcp-config", mcpConfigPath);
1064
- if (existsSync2(claudeMdPath)) claudeArgs.push("--system-prompt-file", claudeMdPath);
1146
+ if (existsSync3(claudeMdPath)) claudeArgs.push("--system-prompt-file", claudeMdPath);
1065
1147
  const acpModelAlias = claudeModelAlias(config.primaryModel);
1066
1148
  if (acpModelAlias) claudeArgs.push("--model", acpModelAlias);
1067
1149
  claudeArgs.push("--allow-dangerously-skip-permissions");
@@ -1073,7 +1155,7 @@ function writeAcpxConfig(config) {
1073
1155
  const envIntegrationsPath = join2(projectDir, ".env.integrations");
1074
1156
  const wrapperPath = join2(projectDir, ".claude", "acpx-agent.sh");
1075
1157
  const wrapperLines = ["#!/usr/bin/env bash"];
1076
- if (existsSync2(envIntegrationsPath)) {
1158
+ if (existsSync3(envIntegrationsPath)) {
1077
1159
  wrapperLines.push(`set -a`, `source ${JSON.stringify(envIntegrationsPath)}`, `set +a`);
1078
1160
  }
1079
1161
  if (claudeAuthMode === "api_key" && anthropicApiKey) {
@@ -1096,6 +1178,8 @@ function writeAcpxConfig(config) {
1096
1178
  }
1097
1179
 
1098
1180
  export {
1181
+ formatMissingVar,
1182
+ probeMcpEnvSubstitution,
1099
1183
  sanitizeMcpJson,
1100
1184
  buildAllowedTools,
1101
1185
  sessionTranscriptDir,
@@ -1125,4 +1209,4 @@ export {
1125
1209
  stopAllSessionsAndWait,
1126
1210
  getProjectDir
1127
1211
  };
1128
- //# sourceMappingURL=chunk-CF3SEPE3.js.map
1212
+ //# sourceMappingURL=chunk-DA3KY3D2.js.map