aismemory 0.5.4 → 0.6.1
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/README.md +51 -0
- package/dist/__tests__/agent-key-mode-e2e.test.d.ts +1 -0
- package/dist/__tests__/agent-key-mode-e2e.test.js +189 -0
- package/dist/__tests__/agent-key-mode-e2e.test.js.map +1 -0
- package/dist/__tests__/agent-key-mode.test.d.ts +1 -0
- package/dist/__tests__/agent-key-mode.test.js +180 -0
- package/dist/__tests__/agent-key-mode.test.js.map +1 -0
- package/dist/__tests__/agent-load-persistence.test.d.ts +1 -0
- package/dist/__tests__/agent-load-persistence.test.js +69 -0
- package/dist/__tests__/agent-load-persistence.test.js.map +1 -0
- package/dist/__tests__/doctor.test.d.ts +1 -0
- package/dist/__tests__/doctor.test.js +248 -0
- package/dist/__tests__/doctor.test.js.map +1 -0
- package/dist/__tests__/pipeline-ingestion.test.js +18 -4
- package/dist/__tests__/pipeline-ingestion.test.js.map +1 -1
- package/dist/__tests__/provisional-token-reauth.test.d.ts +1 -0
- package/dist/__tests__/provisional-token-reauth.test.js +156 -0
- package/dist/__tests__/provisional-token-reauth.test.js.map +1 -0
- package/dist/agent-key-mode.d.ts +36 -0
- package/dist/agent-key-mode.js +183 -0
- package/dist/agent-key-mode.js.map +1 -0
- package/dist/cli/doctor.d.ts +57 -0
- package/dist/cli/doctor.js +332 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/index.js +106 -15
- package/dist/index.js.map +1 -1
- package/dist/prompt-resource.js +1 -1
- package/dist/prompt-resource.js.map +1 -1
- package/dist/tool-args.d.ts +4 -4
- package/package.json +13 -5
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent API key auth mode for the aismemory MCP client (CORBOT-B1D3244C).
|
|
3
|
+
*
|
|
4
|
+
* Unattended-machine auth: a scoped `x-agent-api-key` credential fixed to
|
|
5
|
+
* exactly one agent (AIS_AGENT_ID). No device flow, no OAuth credential
|
|
6
|
+
* file, no DID key-auth — this mode never touches ~/.aismemory/credentials.json
|
|
7
|
+
* or ~/.aismemory/keys/. It exists to kill a duplicate-agent bug: the
|
|
8
|
+
* device-flow fallback mints a fresh provisional agent whenever no cached
|
|
9
|
+
* bond is found, which silently multiplies agents in prod on unattended/CI
|
|
10
|
+
* machines that can never complete a browser bond. This mode refuses to
|
|
11
|
+
* start rather than ever falling back to that path.
|
|
12
|
+
*
|
|
13
|
+
* Server-side contract (packages/agent-identity-service/src/api/middleware/
|
|
14
|
+
* agentApiKeyAuth.ts): the key authenticates ONLY
|
|
15
|
+
* `/v1/agents/:agentId/{memory,goals,dream,full-context}`, and only when
|
|
16
|
+
* :agentId equals the key's own agent. Every other route (tenant-wide agent
|
|
17
|
+
* listing, handoff, personality, key management, ...) is 403'd server-side.
|
|
18
|
+
* This module honors that scope client-side too: tools that need an
|
|
19
|
+
* out-of-scope route return an honest error instead of making a request the
|
|
20
|
+
* server would reject anyway.
|
|
21
|
+
*/
|
|
22
|
+
import { AisHttpError } from './ais-http-error.js';
|
|
23
|
+
import { emitTelemetry } from './telemetry.js';
|
|
24
|
+
import { parseEmptyToolArgs, parseRecallArgs, parseRememberArgs, } from './tool-args.js';
|
|
25
|
+
/** Thrown by loadAgentApiKeyConfig when AIS_AGENT_API_KEY is set without AIS_AGENT_ID. */
|
|
26
|
+
export class AgentApiKeyConfigError extends Error {
|
|
27
|
+
constructor(message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = 'AgentApiKeyConfigError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Read agent-API-key config from the environment.
|
|
34
|
+
*
|
|
35
|
+
* Returns null when AIS_AGENT_API_KEY is unset — the caller falls through to
|
|
36
|
+
* the device-flow/DID-key path. Throws AgentApiKeyConfigError when the key
|
|
37
|
+
* is set but AIS_AGENT_ID is missing; the caller must print the message to
|
|
38
|
+
* stderr and exit nonzero, and must NEVER fall back to the device flow or
|
|
39
|
+
* create a provisional agent (that fallback is the duplicate-agent bug this
|
|
40
|
+
* mode exists to kill).
|
|
41
|
+
*/
|
|
42
|
+
export function loadAgentApiKeyConfig(env = process.env) {
|
|
43
|
+
const rawApiKey = env['AIS_AGENT_API_KEY'];
|
|
44
|
+
// Only a truly ABSENT variable selects the device-flow path. A present-but-
|
|
45
|
+
// empty value is a misconfiguration (e.g. a CI secret that failed to
|
|
46
|
+
// resolve) and must fail fast: silently falling through to the device flow
|
|
47
|
+
// is the exact duplicate-agent bug this mode exists to kill.
|
|
48
|
+
if (rawApiKey === undefined)
|
|
49
|
+
return null;
|
|
50
|
+
// Trim before use: CI secret injection commonly appends a trailing newline,
|
|
51
|
+
// which would land inside the x-agent-api-key header (Node rejects invalid
|
|
52
|
+
// header characters, or the server answers an opaque 401).
|
|
53
|
+
const apiKey = rawApiKey.trim();
|
|
54
|
+
if (apiKey === '') {
|
|
55
|
+
throw new AgentApiKeyConfigError('AIS_AGENT_API_KEY is set but empty (or whitespace-only).\n' +
|
|
56
|
+
'Refusing to start: silently falling back to the device flow could ' +
|
|
57
|
+
'create a duplicate provisional agent.\n' +
|
|
58
|
+
'Unset the variable to use the device flow, or set a real ais_ak_ key.');
|
|
59
|
+
}
|
|
60
|
+
if (!apiKey.startsWith('ais_ak_')) {
|
|
61
|
+
throw new AgentApiKeyConfigError('AIS_AGENT_API_KEY does not look like an agent API key — expected the ' +
|
|
62
|
+
'ais_ak_ prefix. Service keys and JWTs do not work here; mint an ' +
|
|
63
|
+
'agent-scoped API key for this agent and use that.');
|
|
64
|
+
}
|
|
65
|
+
const agentId = env['AIS_AGENT_ID']?.trim();
|
|
66
|
+
if (!agentId) {
|
|
67
|
+
throw new AgentApiKeyConfigError('AIS_AGENT_API_KEY is set but AIS_AGENT_ID is missing.\n' +
|
|
68
|
+
'Agent API keys are scoped to exactly one agent — set AIS_AGENT_ID to the id ' +
|
|
69
|
+
'of the agent this key belongs to (the same agent it was minted for).\n' +
|
|
70
|
+
'Refusing to start: falling back to the device flow or creating a new ' +
|
|
71
|
+
'provisional agent would silently create a duplicate agent.');
|
|
72
|
+
}
|
|
73
|
+
return { apiKey, agentId };
|
|
74
|
+
}
|
|
75
|
+
async function readJson(res) {
|
|
76
|
+
return res.json().catch(() => null);
|
|
77
|
+
}
|
|
78
|
+
export async function aisKeyPost(aisUrl, path, apiKey, body, fetchImpl = globalThis.fetch) {
|
|
79
|
+
const headers = {
|
|
80
|
+
'Content-Type': 'application/json',
|
|
81
|
+
'x-agent-api-key': apiKey,
|
|
82
|
+
};
|
|
83
|
+
let res;
|
|
84
|
+
try {
|
|
85
|
+
res = await fetchImpl(`${aisUrl}${path}`, { method: 'POST', headers, body: JSON.stringify(body) });
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
emitTelemetry({ event: 'ais.http.failure', path, error: err instanceof Error ? err.message : String(err) });
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
const data = await readJson(res);
|
|
92
|
+
if (!res.ok) {
|
|
93
|
+
emitTelemetry({ event: 'ais.http.failure', path, httpStatus: res.status, error: `HTTP ${res.status}` });
|
|
94
|
+
throw new AisHttpError(res.status, path, data);
|
|
95
|
+
}
|
|
96
|
+
return data;
|
|
97
|
+
}
|
|
98
|
+
export async function aisKeyGet(aisUrl, path, apiKey, fetchImpl = globalThis.fetch) {
|
|
99
|
+
let res;
|
|
100
|
+
try {
|
|
101
|
+
res = await fetchImpl(`${aisUrl}${path}`, { headers: { 'x-agent-api-key': apiKey } });
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
emitTelemetry({ event: 'ais.http.failure', path, error: err instanceof Error ? err.message : String(err) });
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
const data = await readJson(res);
|
|
108
|
+
if (!res.ok) {
|
|
109
|
+
emitTelemetry({ event: 'ais.http.failure', path, httpStatus: res.status, error: `HTTP ${res.status}` });
|
|
110
|
+
throw new AisHttpError(res.status, path, data);
|
|
111
|
+
}
|
|
112
|
+
return data;
|
|
113
|
+
}
|
|
114
|
+
// ── Scoped tool dispatch ─────────────────────────────────────────────────
|
|
115
|
+
/** Sentinel returned for a tool name this dispatcher doesn't recognize. */
|
|
116
|
+
export const UNKNOWN_TOOL_KEY_MODE = Symbol('unknown-tool-key-mode');
|
|
117
|
+
/**
|
|
118
|
+
* Error for a tool whose server route falls outside the agent-API-key
|
|
119
|
+
* allowlist (memory, goals, dream, full-context). Thrown instead of ever
|
|
120
|
+
* making the doomed request — the server would 403 it anyway, but failing
|
|
121
|
+
* fast client-side keeps the error message focused on SCOPE rather than a
|
|
122
|
+
* generic 403, and avoids burning a round trip on a request known to fail.
|
|
123
|
+
*/
|
|
124
|
+
export class OutOfScopeToolError extends Error {
|
|
125
|
+
constructor(tool, detail) {
|
|
126
|
+
super(`${tool} is not available with agent API key auth (scoped credential) — ${detail}`);
|
|
127
|
+
this.name = 'OutOfScopeToolError';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export async function dispatchToolKeyMode(aisUrl, config, name, rawArgs, fetchImpl = globalThis.fetch) {
|
|
131
|
+
const { agentId, apiKey } = config;
|
|
132
|
+
switch (name) {
|
|
133
|
+
case 'remember': {
|
|
134
|
+
const args = parseRememberArgs(rawArgs);
|
|
135
|
+
return aisKeyPost(aisUrl, `/v1/agents/${agentId}/memory`, apiKey, {
|
|
136
|
+
content: args.content,
|
|
137
|
+
type: args.type,
|
|
138
|
+
importance: args.importance,
|
|
139
|
+
}, fetchImpl);
|
|
140
|
+
}
|
|
141
|
+
case 'recall': {
|
|
142
|
+
const args = parseRecallArgs(rawArgs);
|
|
143
|
+
const params = new URLSearchParams();
|
|
144
|
+
params.set('query', args.query);
|
|
145
|
+
if (args.limit !== undefined)
|
|
146
|
+
params.set('limit', String(args.limit));
|
|
147
|
+
if (args.type !== undefined)
|
|
148
|
+
params.set('types', args.type);
|
|
149
|
+
return aisKeyGet(aisUrl, `/v1/agents/${agentId}/memory?${params}`, apiKey, fetchImpl);
|
|
150
|
+
}
|
|
151
|
+
case 'full_context':
|
|
152
|
+
parseEmptyToolArgs(rawArgs);
|
|
153
|
+
return aisKeyGet(aisUrl, `/v1/agents/${agentId}/full-context`, apiKey, fetchImpl);
|
|
154
|
+
case 'dream':
|
|
155
|
+
parseEmptyToolArgs(rawArgs);
|
|
156
|
+
return aisKeyPost(aisUrl, `/v1/agents/${agentId}/dream`, apiKey, {}, fetchImpl);
|
|
157
|
+
case 'whoami': {
|
|
158
|
+
parseEmptyToolArgs(rawArgs);
|
|
159
|
+
// No allowed identity route exists for a scoped key: `/v1/agents/:id`
|
|
160
|
+
// has no subresource segment, so the server allowlist regex never
|
|
161
|
+
// matches it and the request would 403. Answer from AIS_AGENT_ID
|
|
162
|
+
// instead, and prove the key is still live with a cheap probe against
|
|
163
|
+
// an allowed route (a 1-result memory read) rather than faking validity.
|
|
164
|
+
await aisKeyGet(aisUrl, `/v1/agents/${agentId}/memory?limit=1`, apiKey, fetchImpl);
|
|
165
|
+
return {
|
|
166
|
+
success: true,
|
|
167
|
+
data: {
|
|
168
|
+
agentId,
|
|
169
|
+
authMode: 'agent-api-key',
|
|
170
|
+
keyValid: true,
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
case 'handoff':
|
|
175
|
+
throw new OutOfScopeToolError('handoff', "the handoff route is outside the key's allowed scope (memory, goals, dream, full-context).");
|
|
176
|
+
case 'agent_load':
|
|
177
|
+
throw new OutOfScopeToolError('agent_load', 'switching agents requires a tenant-wide agent-listing route, which is outside the ' +
|
|
178
|
+
"key's allowed scope. The active agent is fixed to AIS_AGENT_ID for the life of this process.");
|
|
179
|
+
default:
|
|
180
|
+
return UNKNOWN_TOOL_KEY_MODE;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=agent-key-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-key-mode.js","sourceRoot":"","sources":["../src/agent-key-mode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { type OAuthCredentials } from '../oauth-credentials.js';
|
|
3
|
+
export type CheckStatus = 'PASS' | 'WARN' | 'FAIL';
|
|
4
|
+
export interface CheckResult {
|
|
5
|
+
name: string;
|
|
6
|
+
status: CheckStatus;
|
|
7
|
+
message: string;
|
|
8
|
+
hint?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface DoctorReport {
|
|
11
|
+
aisUrl: string;
|
|
12
|
+
checks: CheckResult[];
|
|
13
|
+
problemCount: number;
|
|
14
|
+
verdict: 'pass' | 'problems';
|
|
15
|
+
exitCode: 0 | 1;
|
|
16
|
+
}
|
|
17
|
+
export declare function checkNodeVersion(nodeVersion?: string, minMajor?: number): CheckResult;
|
|
18
|
+
export interface DnsLookupFn {
|
|
19
|
+
(hostname: string): Promise<{
|
|
20
|
+
address: string;
|
|
21
|
+
family: number;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
export declare function checkDnsResolution(host: string, lookup?: DnsLookupFn): Promise<CheckResult>;
|
|
25
|
+
export interface TlsProbeFn {
|
|
26
|
+
(host: string, port: number, timeoutMs: number): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export declare function checkTlsReachability(host: string, probe?: TlsProbeFn, port?: number, timeoutMs?: number): Promise<CheckResult>;
|
|
29
|
+
export type FetchFn = typeof fetch;
|
|
30
|
+
export interface RestHealthResult extends CheckResult {
|
|
31
|
+
/** The `Date` response header, if present — reused by the clock-skew check. */
|
|
32
|
+
dateHeader?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function checkRestHealth(baseUrl: string, fetchImpl?: FetchFn): Promise<RestHealthResult>;
|
|
35
|
+
export declare function checkMcpEndpoint(baseUrl: string, fetchImpl?: FetchFn): Promise<CheckResult>;
|
|
36
|
+
export interface CredentialsCheckDeps {
|
|
37
|
+
load?: (home?: string) => OAuthCredentials | null;
|
|
38
|
+
now?: () => number;
|
|
39
|
+
fetchImpl?: FetchFn;
|
|
40
|
+
home?: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function checkCredentials(baseUrl: string, deps?: CredentialsCheckDeps): Promise<CheckResult>;
|
|
43
|
+
export declare function checkProxyEnv(env?: NodeJS.ProcessEnv): CheckResult;
|
|
44
|
+
export declare function checkClockSkew(dateHeader: string | undefined, now?: () => number, warnThresholdMs?: number): CheckResult;
|
|
45
|
+
export interface DoctorOptions {
|
|
46
|
+
aisUrl?: string;
|
|
47
|
+
env?: NodeJS.ProcessEnv;
|
|
48
|
+
nodeVersion?: string;
|
|
49
|
+
now?: () => number;
|
|
50
|
+
fetchImpl?: FetchFn;
|
|
51
|
+
dnsLookup?: DnsLookupFn;
|
|
52
|
+
tlsProbe?: TlsProbeFn;
|
|
53
|
+
loadCreds?: (home?: string) => OAuthCredentials | null;
|
|
54
|
+
home?: string;
|
|
55
|
+
}
|
|
56
|
+
export declare function runDoctor(options?: DoctorOptions): Promise<DoctorReport>;
|
|
57
|
+
export declare function main(argv?: string[]): Promise<void>;
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `aismemory doctor` — read-only self-diagnosis for "it doesn't work" reports.
|
|
4
|
+
*
|
|
5
|
+
* A new user whose MCP client can't reach AIS has no way to tell whether the
|
|
6
|
+
* problem is DNS, a corporate proxy, an unbonded agent, an expired token, or
|
|
7
|
+
* clock skew. This command runs a fixed set of read-only checks against the
|
|
8
|
+
* local environment and the AIS host and prints a PASS/WARN/FAIL report with
|
|
9
|
+
* a one-line remediation hint per problem — no writes to the API, no agent
|
|
10
|
+
* creation.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* npx aismemory doctor
|
|
14
|
+
* npx aismemory doctor --json
|
|
15
|
+
* AIS_URL=https://other.example.com npx aismemory doctor
|
|
16
|
+
*
|
|
17
|
+
* Exit codes:
|
|
18
|
+
* 0 — no FAIL checks (WARNs are still reported but don't fail the command)
|
|
19
|
+
* 1 — at least one FAIL check
|
|
20
|
+
*/
|
|
21
|
+
import { lookup as dnsLookupDefault } from 'node:dns/promises';
|
|
22
|
+
import { connect as tlsConnectDefault } from 'node:tls';
|
|
23
|
+
import { loadOAuthCredentials, credentialsFilePath } from '../oauth-credentials.js';
|
|
24
|
+
import { isCredsStale } from '../auth-staleness.js';
|
|
25
|
+
/** Minimum Node major version this package requires (per @modelcontextprotocol/sdk engines). */
|
|
26
|
+
const MIN_NODE_MAJOR = 18;
|
|
27
|
+
const PROXY_ENV_KEYS = ['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy', 'NO_PROXY', 'no_proxy'];
|
|
28
|
+
const CLOCK_SKEW_WARN_MS = 5 * 60 * 1000;
|
|
29
|
+
function errMsg(err) {
|
|
30
|
+
return err instanceof Error ? err.message : String(err);
|
|
31
|
+
}
|
|
32
|
+
// ── Individual checks ────────────────────────────────────
|
|
33
|
+
export function checkNodeVersion(nodeVersion = process.version, minMajor = MIN_NODE_MAJOR) {
|
|
34
|
+
const match = /^v?(\d+)\./.exec(nodeVersion);
|
|
35
|
+
const major = match ? Number(match[1]) : NaN;
|
|
36
|
+
if (Number.isNaN(major)) {
|
|
37
|
+
return {
|
|
38
|
+
name: 'Node version',
|
|
39
|
+
status: 'WARN',
|
|
40
|
+
message: `Could not parse Node version string "${nodeVersion}".`,
|
|
41
|
+
hint: `aismemory requires Node >= ${minMajor}.`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (major < minMajor) {
|
|
45
|
+
return {
|
|
46
|
+
name: 'Node version',
|
|
47
|
+
status: 'FAIL',
|
|
48
|
+
message: `Node ${nodeVersion} is below the required minimum (>= ${minMajor}).`,
|
|
49
|
+
hint: `Upgrade Node (e.g. via nvm: "nvm install ${minMajor}") and retry.`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
name: 'Node version',
|
|
54
|
+
status: 'PASS',
|
|
55
|
+
message: `Node ${nodeVersion} meets the minimum requirement (>= ${minMajor}).`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export async function checkDnsResolution(host, lookup = dnsLookupDefault) {
|
|
59
|
+
try {
|
|
60
|
+
const { address } = await lookup(host);
|
|
61
|
+
return {
|
|
62
|
+
name: 'DNS resolution',
|
|
63
|
+
status: 'PASS',
|
|
64
|
+
message: `${host} resolves to ${address}.`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return {
|
|
69
|
+
name: 'DNS resolution',
|
|
70
|
+
status: 'FAIL',
|
|
71
|
+
message: `Could not resolve DNS for ${host}: ${errMsg(err)}.`,
|
|
72
|
+
hint: 'Check your internet connection and DNS settings (or /etc/resolv.conf).',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function defaultTlsProbe(host, port, timeoutMs) {
|
|
77
|
+
return new Promise((resolve, reject) => {
|
|
78
|
+
let settled = false;
|
|
79
|
+
const socket = tlsConnectDefault({ host, port, servername: host, timeout: timeoutMs }, () => {
|
|
80
|
+
if (settled)
|
|
81
|
+
return;
|
|
82
|
+
settled = true;
|
|
83
|
+
socket.end();
|
|
84
|
+
resolve();
|
|
85
|
+
});
|
|
86
|
+
socket.on('error', (err) => {
|
|
87
|
+
if (settled)
|
|
88
|
+
return;
|
|
89
|
+
settled = true;
|
|
90
|
+
reject(err);
|
|
91
|
+
});
|
|
92
|
+
socket.on('timeout', () => {
|
|
93
|
+
if (settled)
|
|
94
|
+
return;
|
|
95
|
+
settled = true;
|
|
96
|
+
socket.destroy();
|
|
97
|
+
reject(new Error(`connection to ${host}:${port} timed out after ${timeoutMs}ms`));
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
export async function checkTlsReachability(host, probe = defaultTlsProbe, port = 443, timeoutMs = 5000) {
|
|
102
|
+
try {
|
|
103
|
+
await probe(host, port, timeoutMs);
|
|
104
|
+
return {
|
|
105
|
+
name: 'TLS reachability',
|
|
106
|
+
status: 'PASS',
|
|
107
|
+
message: `${host}:${port} accepts TLS connections.`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
return {
|
|
112
|
+
name: 'TLS reachability',
|
|
113
|
+
status: 'FAIL',
|
|
114
|
+
message: `Could not open a TLS connection to ${host}:${port}: ${errMsg(err)}.`,
|
|
115
|
+
hint: 'A firewall, VPN, or corporate proxy may be blocking outbound HTTPS. See the proxy check below.',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export async function checkRestHealth(baseUrl, fetchImpl = fetch) {
|
|
120
|
+
const url = `${baseUrl}/livez`;
|
|
121
|
+
try {
|
|
122
|
+
const res = await fetchImpl(url);
|
|
123
|
+
const dateHeader = res.headers.get('date') ?? undefined;
|
|
124
|
+
if (res.ok) {
|
|
125
|
+
return {
|
|
126
|
+
name: 'REST API health',
|
|
127
|
+
status: 'PASS',
|
|
128
|
+
message: `${url} responded HTTP ${res.status} (alive).`,
|
|
129
|
+
dateHeader,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
name: 'REST API health',
|
|
134
|
+
status: 'WARN',
|
|
135
|
+
message: `${url} responded HTTP ${res.status} — server reachable but reporting a problem.`,
|
|
136
|
+
hint: 'The AIS backend may be degraded. Check again shortly.',
|
|
137
|
+
dateHeader,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
return {
|
|
142
|
+
name: 'REST API health',
|
|
143
|
+
status: 'FAIL',
|
|
144
|
+
message: `Could not reach ${url}: ${errMsg(err)}.`,
|
|
145
|
+
hint: 'Check network connectivity — see the DNS/TLS checks above.',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export async function checkMcpEndpoint(baseUrl, fetchImpl = fetch) {
|
|
150
|
+
const url = `${baseUrl}/mcp`;
|
|
151
|
+
try {
|
|
152
|
+
const res = await fetchImpl(url);
|
|
153
|
+
// Any resolved HTTP response (even 401 "auth required") proves the MCP
|
|
154
|
+
// endpoint is reachable — only a network-level failure means "down".
|
|
155
|
+
const authNote = res.status === 401 || res.status === 403 ? ' (auth required, as expected without a key)' : '';
|
|
156
|
+
return {
|
|
157
|
+
name: 'MCP HTTP endpoint',
|
|
158
|
+
status: 'PASS',
|
|
159
|
+
message: `${url} responded HTTP ${res.status}${authNote}.`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
return {
|
|
164
|
+
name: 'MCP HTTP endpoint',
|
|
165
|
+
status: 'FAIL',
|
|
166
|
+
message: `Could not reach ${url}: ${errMsg(err)}.`,
|
|
167
|
+
hint: 'Check network connectivity — see the DNS/TLS checks above.',
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export async function checkCredentials(baseUrl, deps = {}) {
|
|
172
|
+
const load = deps.load ?? loadOAuthCredentials;
|
|
173
|
+
const now = deps.now ?? Date.now;
|
|
174
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
175
|
+
const home = deps.home;
|
|
176
|
+
const path = credentialsFilePath(home);
|
|
177
|
+
const creds = load(home);
|
|
178
|
+
if (!creds) {
|
|
179
|
+
return {
|
|
180
|
+
name: 'Credentials',
|
|
181
|
+
status: 'WARN',
|
|
182
|
+
message: `No credentials found at ${path} — this device has not bonded to an agent yet.`,
|
|
183
|
+
hint: 'Run any aismemory tool from your MCP client once and follow the printed bond URL/code (takes ~30s).',
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (isCredsStale(creds.expiresAt, now())) {
|
|
187
|
+
return {
|
|
188
|
+
name: 'Credentials',
|
|
189
|
+
status: 'WARN',
|
|
190
|
+
message: `Credentials at ${path} are expired or expiring within 5 minutes (expiresAt: ${creds.expiresAt}).`,
|
|
191
|
+
hint: 'No action needed — the next tool call re-authenticates automatically (silently if a device key is enrolled).',
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const res = await fetchImpl(`${baseUrl}/v1/agents/${creds.agentId}`, {
|
|
196
|
+
headers: { Authorization: `Bearer ${creds.token}` },
|
|
197
|
+
});
|
|
198
|
+
if (res.ok) {
|
|
199
|
+
return {
|
|
200
|
+
name: 'Credentials',
|
|
201
|
+
status: 'PASS',
|
|
202
|
+
message: `Bonded as agent ${creds.agentId}; AIS accepted the saved token.`,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
name: 'Credentials',
|
|
207
|
+
status: 'WARN',
|
|
208
|
+
message: `Saved credentials found, but AIS returned HTTP ${res.status} for agent ${creds.agentId}.`,
|
|
209
|
+
hint: 'The token may be revoked or the agent archived. Re-run any aismemory tool to trigger re-authentication.',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
return {
|
|
214
|
+
name: 'Credentials',
|
|
215
|
+
status: 'FAIL',
|
|
216
|
+
message: `Could not verify saved credentials with AIS: ${errMsg(err)}.`,
|
|
217
|
+
hint: 'Check network connectivity — see the REST API health check above.',
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
export function checkProxyEnv(env = process.env) {
|
|
222
|
+
const set = PROXY_ENV_KEYS.filter((key) => Boolean(env[key]));
|
|
223
|
+
if (set.length === 0) {
|
|
224
|
+
return {
|
|
225
|
+
name: 'Proxy environment',
|
|
226
|
+
status: 'PASS',
|
|
227
|
+
message: 'No HTTP(S)_PROXY / NO_PROXY environment variables set.',
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
name: 'Proxy environment',
|
|
232
|
+
status: 'WARN',
|
|
233
|
+
message: `Proxy environment variable(s) detected: ${set.join(', ')}.`,
|
|
234
|
+
hint: 'A corporate proxy can block or MITM TLS to ais.agentsandswarms.ai. If aismemory only fails on this network, ask IT to allowlist the host or trust the proxy CA.',
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
export function checkClockSkew(dateHeader, now = Date.now, warnThresholdMs = CLOCK_SKEW_WARN_MS) {
|
|
238
|
+
if (!dateHeader) {
|
|
239
|
+
return {
|
|
240
|
+
name: 'Clock skew',
|
|
241
|
+
status: 'WARN',
|
|
242
|
+
message: 'No server Date header available to compare (REST API health check did not return one).',
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
const remoteMs = Date.parse(dateHeader);
|
|
246
|
+
if (Number.isNaN(remoteMs)) {
|
|
247
|
+
return {
|
|
248
|
+
name: 'Clock skew',
|
|
249
|
+
status: 'WARN',
|
|
250
|
+
message: `Could not parse the server Date header: "${dateHeader}".`,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const skewMs = Math.abs(now() - remoteMs);
|
|
254
|
+
const skewMinutes = (skewMs / 60000).toFixed(1);
|
|
255
|
+
if (skewMs > warnThresholdMs) {
|
|
256
|
+
return {
|
|
257
|
+
name: 'Clock skew',
|
|
258
|
+
status: 'WARN',
|
|
259
|
+
message: `Local clock differs from the AIS server by ~${skewMinutes} minutes.`,
|
|
260
|
+
hint: 'Large clock skew can invalidate OAuth tokens. Sync your system clock (e.g. enable automatic time/NTP).',
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
name: 'Clock skew',
|
|
265
|
+
status: 'PASS',
|
|
266
|
+
message: `Local clock is within ${skewMinutes} min of the AIS server.`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
export async function runDoctor(options = {}) {
|
|
270
|
+
const env = options.env ?? process.env;
|
|
271
|
+
const aisUrl = options.aisUrl ?? env['AIS_URL'] ?? 'https://ais.agentsandswarms.ai';
|
|
272
|
+
const host = new URL(aisUrl).hostname;
|
|
273
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
274
|
+
const now = options.now ?? Date.now;
|
|
275
|
+
const checks = [];
|
|
276
|
+
checks.push(checkNodeVersion(options.nodeVersion));
|
|
277
|
+
checks.push(await checkDnsResolution(host, options.dnsLookup));
|
|
278
|
+
checks.push(await checkTlsReachability(host, options.tlsProbe));
|
|
279
|
+
const health = await checkRestHealth(aisUrl, fetchImpl);
|
|
280
|
+
checks.push(health);
|
|
281
|
+
checks.push(await checkMcpEndpoint(aisUrl, fetchImpl));
|
|
282
|
+
checks.push(await checkCredentials(aisUrl, {
|
|
283
|
+
fetchImpl,
|
|
284
|
+
load: options.loadCreds,
|
|
285
|
+
home: options.home,
|
|
286
|
+
now,
|
|
287
|
+
}));
|
|
288
|
+
checks.push(checkProxyEnv(env));
|
|
289
|
+
checks.push(checkClockSkew(health.dateHeader, now));
|
|
290
|
+
const problemCount = checks.filter((c) => c.status !== 'PASS').length;
|
|
291
|
+
const hasFail = checks.some((c) => c.status === 'FAIL');
|
|
292
|
+
return {
|
|
293
|
+
aisUrl,
|
|
294
|
+
checks,
|
|
295
|
+
problemCount,
|
|
296
|
+
verdict: problemCount === 0 ? 'pass' : 'problems',
|
|
297
|
+
exitCode: hasFail ? 1 : 0,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
// ── CLI formatting + entrypoint ──────────────────────────
|
|
301
|
+
function formatText(report) {
|
|
302
|
+
const lines = [];
|
|
303
|
+
lines.push(`aismemory doctor — ${report.aisUrl}`);
|
|
304
|
+
lines.push('');
|
|
305
|
+
for (const c of report.checks) {
|
|
306
|
+
lines.push(`[${c.status}] ${c.name}: ${c.message}`);
|
|
307
|
+
if (c.hint && c.status !== 'PASS') {
|
|
308
|
+
lines.push(` hint: ${c.hint}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
lines.push('');
|
|
312
|
+
lines.push(report.problemCount === 0
|
|
313
|
+
? 'doctor: all checks passed'
|
|
314
|
+
: `doctor: ${report.problemCount} problem(s) found`);
|
|
315
|
+
return lines.join('\n');
|
|
316
|
+
}
|
|
317
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
318
|
+
const json = argv.includes('--json');
|
|
319
|
+
const report = await runDoctor();
|
|
320
|
+
if (json) {
|
|
321
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
process.stdout.write(`${formatText(report)}\n`);
|
|
325
|
+
}
|
|
326
|
+
process.exit(report.exitCode);
|
|
327
|
+
}
|
|
328
|
+
main().catch((err) => {
|
|
329
|
+
process.stderr.write(`[aismemory doctor] Fatal: ${errMsg(err)}\n`);
|
|
330
|
+
process.exit(1);
|
|
331
|
+
});
|
|
332
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/cli/doctor.ts"],"names":[],"mappings":"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"}
|