@integrity-labs/agt-cli 0.9.3 → 0.9.5

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.
package/mcp/index.js CHANGED
@@ -14,30 +14,42 @@ if (!AGT_HOST || !AGT_AGENT_ID || (!AGT_TOKEN && !AGT_API_KEY)) {
14
14
  process.exit(1);
15
15
  }
16
16
  // ── Token refresh ───────────────────────────────────────────────────────────
17
- let tokenExpiresAt = Date.now() + 50 * 60_000; // assume ~50min remaining on initial token
17
+ // If no initial token was provided, force an immediate exchange on first call
18
+ let tokenExpiresAt = AGT_TOKEN ? Date.now() + 50 * 60_000 : 0;
19
+ let exchangeInFlight = null;
20
+ async function refreshToken() {
21
+ const res = await fetch(`${AGT_HOST}/host/exchange`, {
22
+ method: 'POST',
23
+ headers: { 'Content-Type': 'application/json' },
24
+ body: JSON.stringify({ host_key: AGT_API_KEY }),
25
+ });
26
+ if (!res.ok) {
27
+ const text = await res.text().catch(() => res.statusText);
28
+ throw new Error(`Token exchange failed: ${res.status} ${text}`);
29
+ }
30
+ const data = (await res.json());
31
+ AGT_TOKEN = data.token;
32
+ tokenExpiresAt = new Date(data.expires_at).getTime();
33
+ return AGT_TOKEN;
34
+ }
18
35
  async function getToken() {
19
- // If we have an API key and the token is expiring soon (within 5 min), refresh
20
- if (AGT_API_KEY && Date.now() > tokenExpiresAt - 5 * 60_000) {
36
+ // If we have an API key and the token is missing or expiring soon (within 5 min), refresh
37
+ if (AGT_API_KEY && (!AGT_TOKEN || Date.now() > tokenExpiresAt - 5 * 60_000)) {
38
+ // Coalesce concurrent refresh calls
39
+ if (!exchangeInFlight) {
40
+ exchangeInFlight = refreshToken().finally(() => { exchangeInFlight = null; });
41
+ }
21
42
  try {
22
- const res = await fetch(`${AGT_HOST}/host/exchange`, {
23
- method: 'POST',
24
- headers: { 'Content-Type': 'application/json' },
25
- body: JSON.stringify({ host_key: AGT_API_KEY }),
26
- });
27
- if (res.ok) {
28
- const data = (await res.json());
29
- AGT_TOKEN = data.token;
30
- tokenExpiresAt = new Date(data.expires_at).getTime();
31
- }
43
+ return await exchangeInFlight;
32
44
  }
33
45
  catch {
34
- // Use existing token if refresh fails
46
+ // Fall through to return existing token (may be stale but avoids crash)
35
47
  }
36
48
  }
37
49
  return AGT_TOKEN;
38
50
  }
39
51
  // ── API client ──────────────────────────────────────────────────────────────
40
- async function apiPost(path, body) {
52
+ async function apiPost(path, body, retried = false) {
41
53
  const controller = new AbortController();
42
54
  const timeout = setTimeout(() => controller.abort(), 15_000);
43
55
  const token = await getToken();
@@ -51,6 +63,12 @@ async function apiPost(path, body) {
51
63
  body: JSON.stringify(body),
52
64
  signal: controller.signal,
53
65
  });
66
+ // Retry once on 401 — token may have expired between cache check and server verification
67
+ if (res.status === 401 && AGT_API_KEY && !retried) {
68
+ clearTimeout(timeout);
69
+ tokenExpiresAt = 0; // force re-exchange
70
+ return apiPost(path, body, true);
71
+ }
54
72
  if (!res.ok) {
55
73
  const text = await res.text().catch(() => res.statusText);
56
74
  throw new Error(`API ${path} returned ${res.status}: ${text}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "description": "Augmented CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "bin": {