nexus-agentd 0.1.0 → 0.1.6

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.
Files changed (44) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +351 -179
  3. package/dist/a2a/runtime.d.ts +30 -0
  4. package/dist/a2a/runtime.js +374 -0
  5. package/dist/acp/runtime.d.ts +12 -3
  6. package/dist/acp/runtime.js +248 -17
  7. package/dist/artifact-store.d.ts +41 -0
  8. package/dist/artifact-store.js +340 -0
  9. package/dist/auth.d.ts +13 -0
  10. package/dist/auth.js +77 -0
  11. package/dist/cli.js +58 -1
  12. package/dist/config.d.ts +10 -0
  13. package/dist/config.js +281 -53
  14. package/dist/control-plane.d.ts +91 -0
  15. package/dist/control-plane.js +629 -0
  16. package/dist/drivers/hermes.d.ts +2 -0
  17. package/dist/drivers/hermes.js +10 -0
  18. package/dist/drivers/index.js +6 -0
  19. package/dist/events.js +13 -2
  20. package/dist/index.d.ts +6 -0
  21. package/dist/index.js +15 -3
  22. package/dist/run-store.d.ts +49 -0
  23. package/dist/run-store.js +291 -0
  24. package/dist/server.d.ts +3 -2
  25. package/dist/server.js +911 -41
  26. package/dist/session-contract.d.ts +16 -4
  27. package/dist/session.d.ts +74 -8
  28. package/dist/session.js +433 -38
  29. package/dist/types.d.ts +193 -6
  30. package/dist/types.js +2 -1
  31. package/dist/webui/app.d.ts +1 -0
  32. package/dist/webui/app.js +1072 -0
  33. package/dist/webui/icons.d.ts +9 -0
  34. package/dist/webui/icons.js +10 -0
  35. package/dist/webui/index.d.ts +3 -0
  36. package/dist/webui/index.js +32 -0
  37. package/dist/webui/markup.d.ts +1 -0
  38. package/dist/webui/markup.js +68 -0
  39. package/dist/webui/styles.d.ts +1 -0
  40. package/dist/webui/styles.js +269 -0
  41. package/dist/workspace-files.d.ts +48 -0
  42. package/dist/workspace-files.js +269 -0
  43. package/nexus-agentd.example.json +30 -27
  44. package/package.json +6 -6
package/dist/config.js CHANGED
@@ -1,6 +1,48 @@
1
- import { readFile } from 'node:fs/promises';
1
+ import { mkdir, open, readFile } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import { agentdDriverKinds } from './types.js';
4
+ export async function ensureAgentdConfig(filePath, options = {}) {
5
+ const absolute = path.resolve(filePath);
6
+ try {
7
+ await readFile(absolute, 'utf8');
8
+ return { created: false };
9
+ }
10
+ catch (error) {
11
+ if (error.code !== 'ENOENT')
12
+ throw error;
13
+ }
14
+ const initial = {
15
+ listen: {
16
+ host: options.host?.trim() || '127.0.0.1',
17
+ port: bootstrapNumber(options.port, 8787, 1, 65535)
18
+ },
19
+ initialized: false,
20
+ workspaceRoots: [path.resolve(options.workspace || process.cwd())],
21
+ sessionTtlMs: 24 * 60 * 60 * 1000,
22
+ promptTimeoutMs: 30 * 60 * 1000,
23
+ cleanupIntervalMs: 60_000,
24
+ apiKeys: [],
25
+ agents: {}
26
+ };
27
+ await mkdir(path.dirname(absolute), { recursive: true });
28
+ try {
29
+ const handle = await open(absolute, 'wx', 0o600);
30
+ try {
31
+ await handle.writeFile(`${JSON.stringify(initial, null, 2)}\n`, 'utf8');
32
+ await handle.sync();
33
+ }
34
+ finally {
35
+ await handle.close();
36
+ }
37
+ return { created: true };
38
+ }
39
+ catch (error) {
40
+ if (error.code === 'EEXIST') {
41
+ return { created: false };
42
+ }
43
+ throw error;
44
+ }
45
+ }
4
46
  export async function loadAgentdConfig(filePath) {
5
47
  const absolute = path.resolve(filePath);
6
48
  const raw = await readFile(absolute, 'utf8');
@@ -13,54 +55,65 @@ export async function loadAgentdConfig(filePath) {
13
55
  }
14
56
  if (!isRecord(value))
15
57
  throw new Error('nexus-agentd config root must be an object');
16
- const listen = isRecord(value.listen) ? value.listen : {};
17
- const host = stringValue(listen.host) || '127.0.0.1';
18
- const port = numberValue(listen.port, 8787, 1, 65535);
19
- const authToken = resolveSecret(stringValue(value.authToken));
20
- if (!authToken)
21
- throw new Error('nexus-agentd authToken is required');
22
- const workspaceRoots = arrayOfStrings(value.workspaceRoots);
58
+ const listen = optionalRecord(value.listen, 'listen') || {};
59
+ const host = optionalString(listen.host, 'listen.host') || '127.0.0.1';
60
+ const port = integerValue(listen.port, 'listen.port', 8787, 1, 65535);
61
+ const initialized = optionalBoolean(value.initialized, 'initialized') ?? true;
62
+ const rawAuthToken = optionalString(value.authToken, 'authToken');
63
+ const authToken = rawAuthToken ? resolveSecret(rawAuthToken) : undefined;
64
+ const adminPasswordHash = optionalString(value.adminPasswordHash, 'adminPasswordHash');
65
+ const apiKeys = parseApiKeys(value.apiKeys);
66
+ if (!initialized && (rawAuthToken || adminPasswordHash || apiKeys.length)) {
67
+ throw new Error('nexus-agentd pending setup must not contain authToken, credentials, or API keys');
68
+ }
69
+ if (initialized && !authToken && !adminPasswordHash && !apiKeys.length) {
70
+ throw new Error('nexus-agentd requires an adminPasswordHash, authToken, or API key after initialization');
71
+ }
72
+ if (authToken && !apiKeys.some((key) => secretsEqual(key.secret, authToken))) {
73
+ apiKeys.unshift({
74
+ id: 'legacy',
75
+ name: 'Legacy Access Key',
76
+ secret: authToken,
77
+ enabled: true,
78
+ scope: { allAgents: true, agentIds: [] },
79
+ createdAt: 0
80
+ });
81
+ }
82
+ const workspaceRoots = stringArray(value.workspaceRoots, 'workspaceRoots');
23
83
  if (!workspaceRoots.length) {
24
84
  throw new Error('nexus-agentd workspaceRoots must contain at least one path');
25
85
  }
26
- if (!isRecord(value.agents)) {
27
- throw new Error('nexus-agentd agents must be an object');
28
- }
86
+ const rawAgents = requiredRecord(value.agents, 'agents');
29
87
  const agents = {};
30
- for (const [id, input] of Object.entries(value.agents)) {
31
- if (!isRecord(input))
32
- throw new Error(`Agent config must be an object: ${id}`);
33
- const driver = stringValue(input.driver) || inferDriver(id);
34
- if (!isAgentdDriverKind(driver)) {
35
- throw new Error(`Unsupported nexus-agentd driver: ${driver || id}`);
36
- }
37
- const permissionPolicy = stringValue(input.permissionPolicy) || 'ask';
38
- if (permissionPolicy !== 'ask' && permissionPolicy !== 'deny') {
39
- throw new Error(`Invalid permissionPolicy for ${id}`);
40
- }
41
- agents[id] = {
42
- driver,
43
- name: optionalString(input.name),
44
- description: optionalString(input.description),
45
- enabled: input.enabled !== false,
46
- command: optionalString(input.command),
47
- args: input.args === undefined ? undefined : arrayOfStrings(input.args),
48
- inheritEnv: input.inheritEnv === undefined
49
- ? undefined
50
- : arrayOfStrings(input.inheritEnv),
51
- env: recordOfStrings(input.env),
52
- permissionPolicy,
53
- permissionTimeoutMs: numberValue(input.permissionTimeoutMs, 15 * 60 * 1000, 1000, 24 * 60 * 60 * 1000)
54
- };
88
+ for (const [id, input] of Object.entries(rawAgents)) {
89
+ agents[id] = parseAgent(id, input);
55
90
  }
56
91
  return {
57
92
  listen: { host, port },
93
+ initialized,
58
94
  authToken,
95
+ adminPasswordHash,
96
+ apiKeys,
59
97
  workspaceRoots,
60
- maxRequestBytes: numberValue(value.maxRequestBytes, 1024 * 1024, 1024, 16 * 1024 * 1024),
61
- maxEventsPerSession: numberValue(value.maxEventsPerSession, 2048, 64, 100_000),
62
- maxOutputChars: numberValue(value.maxOutputChars, 512 * 1024, 16 * 1024, 16 * 1024 * 1024),
63
- sessionTtlMs: numberValue(value.sessionTtlMs, 24 * 60 * 60 * 1000, 60_000, 30 * 24 * 60 * 60 * 1000),
98
+ maxRequestBytes: integerValue(value.maxRequestBytes, 'maxRequestBytes', 1024 * 1024, 1024, 16 * 1024 * 1024),
99
+ maxAttachmentBytes: integerValue(value.maxAttachmentBytes, 'maxAttachmentBytes', 32 * 1024 * 1024, 1024, 64 * 1024 * 1024),
100
+ artifactStoragePath: resolveConfigPath(absolute, optionalString(value.artifactStoragePath, 'artifactStoragePath') || './artifacts'),
101
+ maxArtifactBytes: integerValue(value.maxArtifactBytes, 'maxArtifactBytes', 512 * 1024 * 1024, 1024, 16 * 1024 * 1024 * 1024),
102
+ maxArtifactStorageBytes: integerValue(value.maxArtifactStorageBytes, 'maxArtifactStorageBytes', 4 * 1024 * 1024 * 1024, 1024 * 1024, Number.MAX_SAFE_INTEGER),
103
+ maxPublishedArtifacts: integerValue(value.maxPublishedArtifacts, 'maxPublishedArtifacts', 4096, 1, 1_000_000),
104
+ maxConcurrentArtifactPublishes: integerValue(value.maxConcurrentArtifactPublishes, 'maxConcurrentArtifactPublishes', 4, 1, 128),
105
+ artifactTtlMs: integerValue(value.artifactTtlMs, 'artifactTtlMs', 24 * 60 * 60 * 1000, 60_000, 30 * 24 * 60 * 60 * 1000),
106
+ maxEventsPerSession: integerValue(value.maxEventsPerSession, 'maxEventsPerSession', 2048, 64, 100_000),
107
+ maxOutputChars: integerValue(value.maxOutputChars, 'maxOutputChars', 512 * 1024, 16 * 1024, 16 * 1024 * 1024),
108
+ sessionTtlMs: integerValue(value.sessionTtlMs, 'sessionTtlMs', 24 * 60 * 60 * 1000, 60_000, 30 * 24 * 60 * 60 * 1000),
109
+ cleanupIntervalMs: integerValue(value.cleanupIntervalMs, 'cleanupIntervalMs', 60_000, 5_000, 60 * 60 * 1000),
110
+ requestTimeoutMs: integerValue(value.requestTimeoutMs, 'requestTimeoutMs', 30_000, 1_000, 5 * 60_000),
111
+ promptTimeoutMs: integerValue(value.promptTimeoutMs, 'promptTimeoutMs', 30 * 60_000, 10_000, 24 * 60 * 60 * 1000),
112
+ maxSessions: integerValue(value.maxSessions, 'maxSessions', 64, 1, 10_000),
113
+ maxSseConnections: integerValue(value.maxSseConnections, 'maxSseConnections', 128, 1, 10_000),
114
+ maxConnections: integerValue(value.maxConnections, 'maxConnections', 256, 8, 100_000),
115
+ adminSessionTtlMs: integerValue(value.adminSessionTtlMs, 'adminSessionTtlMs', 12 * 60 * 60 * 1000, 5 * 60_000, 7 * 24 * 60 * 60 * 1000),
116
+ secureAdminCookies: optionalBoolean(value.secureAdminCookies, 'secureAdminCookies') ?? false,
64
117
  agents
65
118
  };
66
119
  }
@@ -75,6 +128,126 @@ export function resolveSecret(value) {
75
128
  throw new Error(`Secret environment variable is missing: ${name}`);
76
129
  return secret;
77
130
  }
131
+ function parseAgent(id, value) {
132
+ const input = requiredRecord(value, `agents.${id}`);
133
+ const protocol = optionalString(input.protocol, `agents.${id}.protocol`) || 'acp';
134
+ if (protocol === 'a2a')
135
+ return parseA2AAgent(id, input);
136
+ if (protocol !== 'acp')
137
+ throw new Error(`Unsupported protocol for ${id}: ${protocol}`);
138
+ const driver = optionalString(input.driver, `agents.${id}.driver`) || inferDriver(id);
139
+ if (!isAgentdDriverKind(driver)) {
140
+ throw new Error(`Unsupported nexus-agentd driver: ${driver || id}`);
141
+ }
142
+ const permissionPolicy = optionalString(input.permissionPolicy, `agents.${id}.permissionPolicy`) || 'ask';
143
+ if (permissionPolicy !== 'ask' && permissionPolicy !== 'deny') {
144
+ throw new Error(`Invalid permissionPolicy for ${id}`);
145
+ }
146
+ const result = {
147
+ protocol: 'acp',
148
+ driver,
149
+ name: optionalString(input.name, `agents.${id}.name`),
150
+ description: optionalString(input.description, `agents.${id}.description`),
151
+ enabled: optionalBoolean(input.enabled, `agents.${id}.enabled`) ?? true,
152
+ workspace: optionalString(input.workspace, `agents.${id}.workspace`),
153
+ command: optionalString(input.command, `agents.${id}.command`),
154
+ args: input.args === undefined
155
+ ? undefined
156
+ : stringArray(input.args, `agents.${id}.args`),
157
+ inheritEnv: input.inheritEnv === undefined
158
+ ? undefined
159
+ : stringArray(input.inheritEnv, `agents.${id}.inheritEnv`),
160
+ env: optionalStringRecord(input.env, `agents.${id}.env`),
161
+ permissionPolicy,
162
+ permissionTimeoutMs: integerValue(input.permissionTimeoutMs, `agents.${id}.permissionTimeoutMs`, 15 * 60 * 1000, 1000, 24 * 60 * 60 * 1000)
163
+ };
164
+ return result;
165
+ }
166
+ function parseA2AAgent(id, input) {
167
+ const agentCardUrl = optionalString(input.agentCardUrl, `agents.${id}.agentCardUrl`);
168
+ const agentUrl = optionalString(input.agentUrl, `agents.${id}.agentUrl`);
169
+ if (!agentCardUrl && !agentUrl) {
170
+ throw new Error(`nexus-agentd agents.${id}.agentCardUrl is required`);
171
+ }
172
+ if (agentCardUrl)
173
+ validateHttpUrl(agentCardUrl, `agents.${id}.agentCardUrl`);
174
+ if (agentUrl)
175
+ validateHttpUrl(agentUrl, `agents.${id}.agentUrl`);
176
+ const preferredTransport = (optionalString(input.preferredTransport, `agents.${id}.preferredTransport`) || 'auto');
177
+ if (!['auto', 'jsonrpc', 'http-json'].includes(preferredTransport)) {
178
+ throw new Error(`Invalid A2A preferredTransport for ${id}`);
179
+ }
180
+ const rawAuth = optionalRecord(input.auth, `agents.${id}.auth`);
181
+ let auth;
182
+ if (rawAuth) {
183
+ const type = (optionalString(rawAuth.type, `agents.${id}.auth.type`) ||
184
+ 'none');
185
+ if (!['none', 'bearer', 'header'].includes(type)) {
186
+ throw new Error(`Invalid A2A auth type for ${id}`);
187
+ }
188
+ const rawValue = optionalString(rawAuth.value, `agents.${id}.auth.value`);
189
+ const headerName = optionalString(rawAuth.headerName, `agents.${id}.auth.headerName`);
190
+ if (type !== 'none' && !rawValue) {
191
+ throw new Error(`A2A auth value is required for ${id}`);
192
+ }
193
+ if (type === 'header' && !validHeaderName(headerName || '')) {
194
+ throw new Error(`A valid A2A auth headerName is required for ${id}`);
195
+ }
196
+ auth = {
197
+ type,
198
+ value: rawValue ? resolveSecret(rawValue) : undefined,
199
+ headerName: type === 'header' ? headerName : undefined
200
+ };
201
+ }
202
+ return {
203
+ protocol: 'a2a',
204
+ name: optionalString(input.name, `agents.${id}.name`),
205
+ description: optionalString(input.description, `agents.${id}.description`),
206
+ enabled: optionalBoolean(input.enabled, `agents.${id}.enabled`) ?? true,
207
+ agentCardUrl,
208
+ agentUrl,
209
+ preferredTransport,
210
+ auth,
211
+ timeoutMs: integerValue(input.timeoutMs, `agents.${id}.timeoutMs`, 60_000, 1_000, 30 * 60_000)
212
+ };
213
+ }
214
+ function parseApiKeys(value) {
215
+ if (value === undefined)
216
+ return [];
217
+ if (!Array.isArray(value))
218
+ throw new Error('nexus-agentd apiKeys must be an array');
219
+ const ids = new Set();
220
+ return value.map((entry, index) => {
221
+ const item = requiredRecord(entry, `apiKeys[${index}]`);
222
+ const id = requiredString(item.id, `apiKeys[${index}].id`);
223
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(id)) {
224
+ throw new Error(`Invalid API key id: ${id}`);
225
+ }
226
+ if (ids.has(id))
227
+ throw new Error(`Duplicate API key id: ${id}`);
228
+ ids.add(id);
229
+ const rawSecret = requiredString(item.secret, `apiKeys[${index}].secret`);
230
+ const scope = requiredRecord(item.scope, `apiKeys[${index}].scope`);
231
+ const allAgents = optionalBoolean(scope.allAgents, `apiKeys[${index}].scope.allAgents`);
232
+ if (allAgents === undefined) {
233
+ throw new Error(`apiKeys[${index}].scope.allAgents is required`);
234
+ }
235
+ return {
236
+ id,
237
+ name: requiredString(item.name, `apiKeys[${index}].name`),
238
+ secret: resolveSecret(rawSecret),
239
+ enabled: optionalBoolean(item.enabled, `apiKeys[${index}].enabled`) ?? true,
240
+ scope: {
241
+ allAgents,
242
+ agentIds: stringArray(scope.agentIds ?? [], `apiKeys[${index}].scope.agentIds`)
243
+ },
244
+ createdAt: integerValue(item.createdAt, `apiKeys[${index}].createdAt`, 0, 0, Number.MAX_SAFE_INTEGER),
245
+ lastUsedAt: item.lastUsedAt === undefined
246
+ ? undefined
247
+ : integerValue(item.lastUsedAt, `apiKeys[${index}].lastUsedAt`, 0, 0, Number.MAX_SAFE_INTEGER)
248
+ };
249
+ });
250
+ }
78
251
  function inferDriver(id) {
79
252
  const value = id.trim().toLowerCase();
80
253
  return isAgentdDriverKind(value) ? value : '';
@@ -82,34 +255,89 @@ function inferDriver(id) {
82
255
  function isAgentdDriverKind(value) {
83
256
  return agentdDriverKinds.includes(value);
84
257
  }
258
+ function requiredRecord(value, name) {
259
+ if (!isRecord(value))
260
+ throw new Error(`nexus-agentd ${name} must be an object`);
261
+ return value;
262
+ }
263
+ function optionalRecord(value, name) {
264
+ if (value === undefined)
265
+ return undefined;
266
+ return requiredRecord(value, name);
267
+ }
85
268
  function isRecord(value) {
86
269
  return Boolean(value && typeof value === 'object' && !Array.isArray(value));
87
270
  }
88
- function stringValue(value) {
89
- return typeof value === 'string' ? value.trim() : '';
271
+ function requiredString(value, name) {
272
+ const result = optionalString(value, name);
273
+ if (!result)
274
+ throw new Error(`nexus-agentd ${name} is required`);
275
+ return result;
90
276
  }
91
- function optionalString(value) {
92
- return stringValue(value) || undefined;
277
+ function optionalString(value, name) {
278
+ if (value === undefined || value === null)
279
+ return undefined;
280
+ if (typeof value !== 'string')
281
+ throw new Error(`nexus-agentd ${name} must be a string`);
282
+ return value.trim() || undefined;
93
283
  }
94
- function arrayOfStrings(value) {
284
+ function optionalBoolean(value, name) {
285
+ if (value === undefined)
286
+ return undefined;
287
+ if (typeof value !== 'boolean')
288
+ throw new Error(`nexus-agentd ${name} must be a boolean`);
289
+ return value;
290
+ }
291
+ function stringArray(value, name) {
95
292
  if (!Array.isArray(value))
96
- return [];
97
- return value.map(stringValue).filter(Boolean);
293
+ throw new Error(`nexus-agentd ${name} must be an array`);
294
+ return value.map((entry, index) => requiredString(entry, `${name}[${index}]`));
98
295
  }
99
- function recordOfStrings(value) {
100
- if (!isRecord(value))
296
+ function optionalStringRecord(value, name) {
297
+ if (value === undefined)
101
298
  return undefined;
299
+ const input = requiredRecord(value, name);
102
300
  const result = {};
103
- for (const [key, item] of Object.entries(value)) {
104
- if (typeof item !== 'string')
105
- continue;
301
+ for (const [key, item] of Object.entries(input)) {
302
+ if (typeof item !== 'string') {
303
+ throw new Error(`nexus-agentd ${name}.${key} must be a string`);
304
+ }
106
305
  result[key] = item;
107
306
  }
108
307
  return result;
109
308
  }
110
- function numberValue(value, fallback, min, max) {
309
+ function integerValue(value, name, fallback, min, max) {
310
+ if (value === undefined)
311
+ return fallback;
312
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < min || value > max) {
313
+ throw new Error(`nexus-agentd ${name} must be an integer between ${min} and ${max}`);
314
+ }
315
+ return value;
316
+ }
317
+ function bootstrapNumber(value, fallback, min, max) {
111
318
  const number = Number(value);
112
319
  if (!Number.isFinite(number))
113
320
  return fallback;
114
321
  return Math.min(max, Math.max(min, Math.trunc(number)));
115
322
  }
323
+ function validHeaderName(value) {
324
+ return /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(value);
325
+ }
326
+ function validateHttpUrl(value, name) {
327
+ let url;
328
+ try {
329
+ url = new URL(value);
330
+ }
331
+ catch {
332
+ throw new Error(`nexus-agentd ${name} must be a valid URL`);
333
+ }
334
+ if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.hash) {
335
+ throw new Error(`nexus-agentd ${name} must be an http(s) URL without credentials or a fragment`);
336
+ }
337
+ }
338
+ function resolveConfigPath(configPath, value) {
339
+ return path.resolve(path.dirname(configPath), value);
340
+ }
341
+ function secretsEqual(left, right) {
342
+ return left.length === right.length && left === right;
343
+ }
@@ -0,0 +1,91 @@
1
+ import type { SessionManager } from './session.js';
2
+ import { type A2AAuthType, type A2ATransportPreference, type AgentdApiKeyPrincipal, type AgentdApiKeyScope, type AgentdApiKeyView, type AgentdConfig, type AgentdControlPlaneView, type AgentdDriverKind, type AgentdProtocol, type PermissionPolicy } from './types.js';
3
+ export interface AgentdAgentUpdate {
4
+ protocol?: AgentdProtocol;
5
+ driver?: AgentdDriverKind;
6
+ name?: string;
7
+ description?: string;
8
+ enabled?: boolean;
9
+ workspace?: string;
10
+ permissionPolicy?: PermissionPolicy;
11
+ permissionTimeoutMs?: number;
12
+ agentCardUrl?: string;
13
+ agentUrl?: string;
14
+ preferredTransport?: A2ATransportPreference;
15
+ authType?: A2AAuthType;
16
+ authValue?: string;
17
+ authHeaderName?: string;
18
+ timeoutMs?: number;
19
+ }
20
+ export interface AgentdApiKeyUpdate {
21
+ name?: string;
22
+ enabled?: boolean;
23
+ scope?: AgentdApiKeyScope;
24
+ }
25
+ export interface AgentdRuntimeSettingsUpdate {
26
+ sessionTtlMs: number;
27
+ promptTimeoutMs: number;
28
+ cleanupIntervalMs: number;
29
+ }
30
+ export declare class AgentdControlPlane {
31
+ private readonly configPath;
32
+ private config;
33
+ private readonly sessions;
34
+ private queue;
35
+ private usageTimer?;
36
+ constructor(configPath: string, config: AgentdConfig, sessions: SessionManager);
37
+ snapshot(): AgentdControlPlaneView;
38
+ isInitialized(): boolean;
39
+ needsAdminSetup(): boolean;
40
+ /** @deprecated Legacy data-plane key accessor. */
41
+ accessKey(): string | undefined;
42
+ initializeAdminPassword(passwordInput: string, confirmationInput: string): Promise<{
43
+ initialized: true;
44
+ adminSetupRequired: false;
45
+ }>;
46
+ /** @deprecated Kept as a clear error for integrations using the old bootstrap API. */
47
+ initializeAccessKey(): void;
48
+ verifyAdminPassword(password: string): Promise<boolean>;
49
+ changeAdminPassword(current: string, next: string, confirmation: string): Promise<{
50
+ changed: true;
51
+ }>;
52
+ authenticateApiKey(secret: string): AgentdApiKeyPrincipal | undefined;
53
+ listApiKeys(): AgentdApiKeyView[];
54
+ createApiKey(nameInput: string, scopeInput: AgentdApiKeyScope, customSecret?: string): Promise<{
55
+ key: AgentdApiKeyView;
56
+ secret: string;
57
+ }>;
58
+ updateApiKey(idInput: string, update: AgentdApiKeyUpdate): Promise<AgentdApiKeyView>;
59
+ deleteApiKey(idInput: string): Promise<{
60
+ deleted: true;
61
+ }>;
62
+ revealApiKey(idInput: string): {
63
+ secret: string;
64
+ };
65
+ regenerateApiKey(idInput: string): Promise<{
66
+ key: AgentdApiKeyView;
67
+ secret: string;
68
+ }>;
69
+ /** @deprecated Rotates the migrated legacy key when present. */
70
+ rotateAccessKey(): Promise<{
71
+ accessKey: string;
72
+ }>;
73
+ putWorkspaceRoots(values: string[]): Promise<AgentdControlPlaneView>;
74
+ putRuntimeSettings(update: AgentdRuntimeSettingsUpdate): Promise<AgentdControlPlaneView>;
75
+ putAgent(idInput: string, update: AgentdAgentUpdate): Promise<AgentdControlPlaneView>;
76
+ deleteAgent(idInput: string): Promise<AgentdControlPlaneView>;
77
+ private updateAgents;
78
+ private validateScope;
79
+ private requireApiKey;
80
+ private apiKeyView;
81
+ private markApiKeyUsed;
82
+ private rawApiKeys;
83
+ private readRawConfig;
84
+ private persist;
85
+ private agentView;
86
+ private exclusive;
87
+ }
88
+ export declare class ControlPlaneError extends Error {
89
+ readonly status: number;
90
+ constructor(status: number, message: string);
91
+ }