nexus-agentd 0.2.5 → 0.3.0

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 (61) hide show
  1. package/README.md +359 -250
  2. package/dist/a2a/runtime.d.ts +7 -1
  3. package/dist/a2a/runtime.js +290 -17
  4. package/dist/acp/runtime.d.ts +5 -1
  5. package/dist/acp/runtime.js +88 -39
  6. package/dist/artifact-store.d.ts +162 -0
  7. package/dist/artifact-store.js +1081 -0
  8. package/dist/cli.js +13 -14
  9. package/dist/completion-contract.js +1 -1
  10. package/dist/config.js +45 -5
  11. package/dist/control-plane-validation.d.ts +54 -0
  12. package/dist/control-plane-validation.js +152 -0
  13. package/dist/control-plane.d.ts +9 -32
  14. package/dist/control-plane.js +52 -158
  15. package/dist/drivers/index.js +12 -0
  16. package/dist/drivers/pi.js +1 -1
  17. package/dist/drivers/stdio.d.ts +4 -1
  18. package/dist/drivers/stdio.js +135 -19
  19. package/dist/events.d.ts +9 -0
  20. package/dist/events.js +17 -4
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +33 -6
  23. package/dist/process-tree.js +15 -6
  24. package/dist/run-store.d.ts +57 -7
  25. package/dist/run-store.js +188 -23
  26. package/dist/server/auth-policy.d.ts +27 -0
  27. package/dist/server/auth-policy.js +143 -0
  28. package/dist/server/connection.d.ts +8 -0
  29. package/dist/server/connection.js +67 -0
  30. package/dist/server/diagnostics.d.ts +40 -0
  31. package/dist/server/diagnostics.js +130 -0
  32. package/dist/server/metrics.d.ts +51 -0
  33. package/dist/server/metrics.js +56 -0
  34. package/dist/server/quota.d.ts +59 -0
  35. package/dist/server/quota.js +176 -0
  36. package/dist/server/validation.d.ts +29 -0
  37. package/dist/server/validation.js +221 -0
  38. package/dist/server.d.ts +3 -0
  39. package/dist/server.js +682 -418
  40. package/dist/session/admin-runs.d.ts +73 -0
  41. package/dist/session/admin-runs.js +297 -0
  42. package/dist/session/admission.d.ts +32 -0
  43. package/dist/session/admission.js +62 -0
  44. package/dist/session/readiness.d.ts +33 -0
  45. package/dist/session/readiness.js +174 -0
  46. package/dist/session-contract.d.ts +1 -0
  47. package/dist/session.d.ts +64 -7
  48. package/dist/session.js +321 -159
  49. package/dist/sse-writer.d.ts +7 -0
  50. package/dist/sse-writer.js +60 -0
  51. package/dist/types.d.ts +44 -2
  52. package/dist/types.js +1 -0
  53. package/dist/webui/app/sources.js +18 -10
  54. package/dist/webui/index.js +11 -11
  55. package/dist/webui/markup.js +69 -66
  56. package/dist/webui/styles.js +791 -616
  57. package/dist/workspace.d.ts +30 -0
  58. package/dist/workspace.js +67 -2
  59. package/examples/client.mjs +102 -0
  60. package/nexus-agentd.example.json +21 -2
  61. package/package.json +6 -3
package/dist/cli.js CHANGED
@@ -18,22 +18,21 @@ const label = typeof address === 'object' && address
18
18
  console.log(`nexus-agentd listening on ${label}`);
19
19
  for (const url of displayUrls(address))
20
20
  console.log(`WebUI: ${url}`);
21
- if (bootstrap.created) {
21
+ if (bootstrap.created)
22
22
  console.log(`Created config: ${configPath}`);
23
- console.log('Setup required: open the WebUI and create the Console Password.');
24
- if (runtime.config.listen.host !== '127.0.0.1' && runtime.config.listen.host !== '::1') {
25
- console.warn('WARNING: first-run setup is reachable over the network; initialize it immediately on a trusted network.');
26
- }
23
+ if (runtime.controlPlane.setupToken) {
24
+ console.log('Setup required: enter the following one-time setup token in the WebUI, then create the Console Password.');
25
+ console.log(`Setup token: ${runtime.controlPlane.setupToken}`);
26
+ console.warn('Keep this token private. It changes on restart. Use a trusted network or HTTPS for remote setup.');
27
27
  }
28
- let closing = false;
29
- const close = async () => {
30
- if (closing)
31
- return;
32
- closing = true;
33
- await runtime.close();
34
- };
35
- process.once('SIGINT', () => void close().finally(() => process.exit(0)));
36
- process.once('SIGTERM', () => void close().finally(() => process.exit(0)));
28
+ let closing;
29
+ const close = () => closing ??= runtime.close();
30
+ const shutdown = () => void close().then(() => process.exit(0), (error) => {
31
+ console.error(JSON.stringify({ level: 'error', event: 'shutdown_failed', message: error instanceof Error ? error.message : String(error) }));
32
+ process.exit(1);
33
+ });
34
+ process.once('SIGINT', shutdown);
35
+ process.once('SIGTERM', shutdown);
37
36
  function resolveConfigPath(args) {
38
37
  const index = args.indexOf('--config');
39
38
  const value = index >= 0 ? args[index + 1] : process.env.NEXUS_AGENTD_CONFIG;
@@ -4,6 +4,6 @@ export const TURN_COMPLETION_CONTRACT = [
4
4
  'If you need user input or permission, use the protocol input/permission request and wait for the response.',
5
5
  'Before ending the turn, verify the requested work and provide a non-empty final response.',
6
6
  'The final response must summarize the outcome, verification performed, and workspace-relative paths for generated files.',
7
- 'Attach generated resources or artifacts through the protocol when supported. If the runtime only reports a local deliverable path, put each requested file on its own final line as MEDIA:<path>; Agent Nexus will snapshot that explicitly declared file as an artifact before the turn completes.',
7
+ 'Attach generated resources or artifacts through the protocol when supported. If the runtime only reports a local deliverable path, put each requested file on its own final line as MEDIA:<path>, where <path> stays inside the configured workspace roots; Agent Nexus snapshots that declared file as an artifact before the turn completes, refuses paths outside those roots, and attaches at most 8 files per turn.',
8
8
  '</agent_nexus_completion_contract>'
9
9
  ].join('\n');
package/dist/config.js CHANGED
@@ -13,7 +13,7 @@ export async function ensureAgentdConfig(filePath, options = {}) {
13
13
  }
14
14
  const initial = {
15
15
  listen: {
16
- host: options.host?.trim() || '127.0.0.1',
16
+ host: options.host?.trim() || '0.0.0.0',
17
17
  port: bootstrapNumber(options.port, 8787, 1, 65535)
18
18
  },
19
19
  initialized: false,
@@ -56,7 +56,7 @@ export async function loadAgentdConfig(filePath) {
56
56
  if (!isRecord(value))
57
57
  throw new Error('nexus-agentd config root must be an object');
58
58
  const listen = optionalRecord(value.listen, 'listen') || {};
59
- const host = optionalString(listen.host, 'listen.host') || '127.0.0.1';
59
+ const host = optionalString(listen.host, 'listen.host') || '0.0.0.0';
60
60
  const port = integerValue(listen.port, 'listen.port', 8787, 1, 65535);
61
61
  const initialized = optionalBoolean(value.initialized, 'initialized') ?? true;
62
62
  const rawAuthToken = optionalString(value.authToken, 'authToken');
@@ -84,17 +84,45 @@ export async function loadAgentdConfig(filePath) {
84
84
  throw new Error('nexus-agentd workspaceRoots must contain at least one path');
85
85
  }
86
86
  const rawAgents = requiredRecord(value.agents, 'agents');
87
- const agents = {};
87
+ const agents = Object.create(null);
88
88
  for (const [id, input] of Object.entries(rawAgents)) {
89
89
  agents[id] = parseAgent(id, input);
90
90
  }
91
+ const quotas = optionalRecord(value.quotas, 'quotas') || {};
92
+ const history = optionalRecord(value.history, 'history') || {};
93
+ const artifacts = optionalRecord(value.artifacts, 'artifacts') || {};
94
+ const maxSessions = integerValue(value.maxSessions, 'maxSessions', 64, 1, 10_000);
95
+ const maxSseConnections = integerValue(value.maxSseConnections, 'maxSseConnections', 128, 1, 10_000);
91
96
  return {
92
97
  listen: { host, port },
98
+ publicOrigins: value.publicOrigins === undefined ? [] : stringArray(value.publicOrigins, 'publicOrigins').map((origin) => {
99
+ validateHttpUrl(origin, 'publicOrigins');
100
+ if (new URL(origin).origin !== origin)
101
+ throw new Error('publicOrigins must contain exact origins without paths');
102
+ return origin;
103
+ }),
93
104
  initialized,
94
105
  authToken,
95
106
  adminPasswordHash,
96
107
  apiKeys,
97
108
  workspaceRoots,
109
+ quotas: {
110
+ maxSessionsPerKey: integerValue(quotas.maxSessionsPerKey, 'quotas.maxSessionsPerKey', Math.min(16, maxSessions), 1, 10_000),
111
+ maxRunningRunsPerKey: integerValue(quotas.maxRunningRunsPerKey, 'quotas.maxRunningRunsPerKey', Math.min(4, maxSessions), 1, 10_000),
112
+ maxSsePerKey: integerValue(quotas.maxSsePerKey, 'quotas.maxSsePerKey', Math.min(8, maxSseConnections), 1, 10_000),
113
+ maxUploadBytesPerKey: integerValue(quotas.maxUploadBytesPerKey, 'quotas.maxUploadBytesPerKey', 32 * 1024 * 1024, 1024, 1024 * 1024 * 1024)
114
+ },
115
+ history: {
116
+ maxRuns: integerValue(history.maxRuns, 'history.maxRuns', 1000, 1, 100_000),
117
+ retentionDays: integerValue(history.retentionDays, 'history.retentionDays', 30, 1, 3650),
118
+ maxBytes: integerValue(history.maxBytes, 'history.maxBytes', 64 * 1024 * 1024, 1024, 1024 * 1024 * 1024)
119
+ },
120
+ artifacts: {
121
+ retentionDays: integerValue(artifacts.retentionDays, 'artifacts.retentionDays', 30, 1, 3650),
122
+ maxBytes: integerValue(artifacts.maxBytes, 'artifacts.maxBytes', 512 * 1024 * 1024, 1024, 1024 ** 4),
123
+ maxArtifactBytes: integerValue(artifacts.maxArtifactBytes, 'artifacts.maxArtifactBytes', 12 * 1024 * 1024, 1024, 12 * 1024 * 1024),
124
+ maxQueuedBytes: integerValue(artifacts.maxQueuedBytes, 'artifacts.maxQueuedBytes', 64 * 1024 * 1024, 1024, 512 * 1024 * 1024)
125
+ },
98
126
  maxRequestBytes: integerValue(value.maxRequestBytes, 'maxRequestBytes', 1024 * 1024, 1024, 16 * 1024 * 1024),
99
127
  maxAttachmentBytes: integerValue(value.maxAttachmentBytes, 'maxAttachmentBytes', 32 * 1024 * 1024, 1024, 64 * 1024 * 1024),
100
128
  maxEventsPerSession: integerValue(value.maxEventsPerSession, 'maxEventsPerSession', 2048, 64, 100_000),
@@ -103,7 +131,7 @@ export async function loadAgentdConfig(filePath) {
103
131
  cleanupIntervalMs: integerValue(value.cleanupIntervalMs, 'cleanupIntervalMs', 60_000, 5_000, 60 * 60 * 1000),
104
132
  requestTimeoutMs: integerValue(value.requestTimeoutMs, 'requestTimeoutMs', 30_000, 1_000, 5 * 60_000),
105
133
  promptTimeoutMs: integerValue(value.promptTimeoutMs, 'promptTimeoutMs', 30 * 60_000, 10_000, 24 * 60 * 60 * 1000),
106
- maxSessions: integerValue(value.maxSessions, 'maxSessions', 64, 1, 10_000),
134
+ maxSessions,
107
135
  maxSseConnections: integerValue(value.maxSseConnections, 'maxSseConnections', 128, 1, 10_000),
108
136
  maxConnections: integerValue(value.maxConnections, 'maxConnections', 256, 8, 100_000),
109
137
  adminSessionTtlMs: integerValue(value.adminSessionTtlMs, 'adminSessionTtlMs', 12 * 60 * 60 * 1000, 5 * 60_000, 7 * 24 * 60 * 60 * 1000),
@@ -150,6 +178,9 @@ function parseAgent(id, value) {
150
178
  args: input.args === undefined
151
179
  ? undefined
152
180
  : stringArray(input.args, `agents.${id}.args`),
181
+ probeArgs: input.probeArgs === undefined
182
+ ? undefined
183
+ : stringArray(input.probeArgs, `agents.${id}.probeArgs`),
153
184
  inheritEnv: input.inheritEnv === undefined
154
185
  ? undefined
155
186
  : stringArray(input.inheritEnv, `agents.${id}.inheritEnv`),
@@ -157,6 +188,9 @@ function parseAgent(id, value) {
157
188
  permissionPolicy,
158
189
  permissionTimeoutMs: integerValue(input.permissionTimeoutMs, `agents.${id}.permissionTimeoutMs`, 15 * 60 * 1000, 1000, 24 * 60 * 60 * 1000)
159
190
  };
191
+ if (driver === 'stdio' && !result.command) {
192
+ throw new Error(`nexus-agentd agents.${id}.command is required for the stdio driver`);
193
+ }
160
194
  return result;
161
195
  }
162
196
  function parseA2AAgent(id, input) {
@@ -204,7 +238,13 @@ function parseA2AAgent(id, input) {
204
238
  agentUrl,
205
239
  preferredTransport,
206
240
  auth,
207
- timeoutMs: integerValue(input.timeoutMs, `agents.${id}.timeoutMs`, 60_000, 1_000, 30 * 60_000)
241
+ timeoutMs: integerValue(input.timeoutMs, `agents.${id}.timeoutMs`, 60_000, 1_000, 30 * 60_000),
242
+ taskTimeoutMs: input.taskTimeoutMs === undefined
243
+ ? undefined
244
+ : integerValue(input.taskTimeoutMs, `agents.${id}.taskTimeoutMs`, 30 * 60_000, 10_000, 24 * 60 * 60 * 1000),
245
+ streamIdleTimeoutMs: input.streamIdleTimeoutMs === undefined
246
+ ? undefined
247
+ : integerValue(input.streamIdleTimeoutMs, `agents.${id}.streamIdleTimeoutMs`, 60_000, 1_000, 30 * 60_000)
208
248
  };
209
249
  }
210
250
  function parseApiKeys(value) {
@@ -0,0 +1,54 @@
1
+ import type { AgentdProtocol, AgentdDriverKind, PermissionPolicy, A2ATransportPreference, A2AAuthType, AgentdApiKeyScope } from './types.js';
2
+ export interface AgentdAgentUpdate {
3
+ protocol?: AgentdProtocol;
4
+ driver?: AgentdDriverKind;
5
+ name?: string;
6
+ description?: string;
7
+ enabled?: boolean;
8
+ workspace?: string;
9
+ permissionPolicy?: PermissionPolicy;
10
+ permissionTimeoutMs?: number;
11
+ agentCardUrl?: string;
12
+ agentUrl?: string;
13
+ preferredTransport?: A2ATransportPreference;
14
+ authType?: A2AAuthType;
15
+ authValue?: string;
16
+ authHeaderName?: string;
17
+ timeoutMs?: number;
18
+ taskTimeoutMs?: number | null;
19
+ streamIdleTimeoutMs?: number | null;
20
+ }
21
+ export interface AgentdApiKeyUpdate {
22
+ name?: string;
23
+ enabled?: boolean;
24
+ scope?: AgentdApiKeyScope;
25
+ }
26
+ export interface AgentdRuntimeSettingsUpdate {
27
+ sessionTtlMs: number;
28
+ promptTimeoutMs: number;
29
+ cleanupIntervalMs: number;
30
+ }
31
+ export declare class ControlPlaneError extends Error {
32
+ readonly status: number;
33
+ constructor(status: number, message: string);
34
+ }
35
+ export declare function validateRuntimeSettings(update: AgentdRuntimeSettingsUpdate): void;
36
+ export declare function validateIntegerRange(value: number, min: number, max: number, name: string): void;
37
+ export declare function validateUpdate(update: AgentdAgentUpdate): void;
38
+ export declare function validateAgentId(value: string): string;
39
+ export declare function validateOpaqueId(value: string, label: string): string;
40
+ export declare function validatePassword(value: string, confirmation: string): string;
41
+ export declare function validateKeyName(value: string): string;
42
+ export declare function validateApiKeySecret(value: string): string;
43
+ export declare function validateA2ASecret(value: string): string;
44
+ export declare function validateAgentUrl(value: string): string;
45
+ export declare function defaultAgentCardUrl(agentUrl: string | undefined): string | undefined;
46
+ export declare function clampTimeout(value: number | undefined, fallback: number, min: number, max: number): number;
47
+ export declare function preservedAcpAdvanced(previous: Record<string, unknown>): Record<string, unknown>;
48
+ export declare function setOptionalString(target: Record<string, unknown>, key: string, value: string | undefined): void;
49
+ export declare function validHeaderName(value: string): boolean;
50
+ export declare function safeSecretEqual(left: string, right: string): boolean;
51
+ export declare function cleanString(value: unknown): string;
52
+ export declare function recordValue(value: unknown): Record<string, any>;
53
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
54
+ export declare function errorMessage(error: unknown): string;
@@ -0,0 +1,152 @@
1
+ import { timingSafeEqual } from 'node:crypto';
2
+ import { validateAdminPassword } from './auth.js';
3
+ export class ControlPlaneError extends Error {
4
+ status;
5
+ constructor(status, message) {
6
+ super(message);
7
+ this.status = status;
8
+ }
9
+ }
10
+ export function validateRuntimeSettings(update) {
11
+ validateIntegerRange(update.sessionTtlMs, 60_000, 30 * 24 * 60 * 60 * 1000, 'sessionTtlMs');
12
+ validateIntegerRange(update.promptTimeoutMs, 10_000, 24 * 60 * 60 * 1000, 'promptTimeoutMs');
13
+ validateIntegerRange(update.cleanupIntervalMs, 5_000, 60 * 60 * 1000, 'cleanupIntervalMs');
14
+ }
15
+ export function validateIntegerRange(value, min, max, name) {
16
+ if (!Number.isInteger(value) || value < min || value > max) {
17
+ throw new ControlPlaneError(400, `${name} must be between ${min} and ${max}`);
18
+ }
19
+ }
20
+ export function validateUpdate(update) {
21
+ if (update.protocol !== undefined && update.protocol !== 'acp' && update.protocol !== 'a2a') {
22
+ throw new ControlPlaneError(400, 'protocol must be acp or a2a');
23
+ }
24
+ if (update.permissionPolicy !== undefined &&
25
+ update.permissionPolicy !== 'ask' &&
26
+ update.permissionPolicy !== 'allow' &&
27
+ update.permissionPolicy !== 'deny') {
28
+ throw new ControlPlaneError(400, 'permissionPolicy must be ask, allow, or deny');
29
+ }
30
+ if (update.preferredTransport !== undefined &&
31
+ !['auto', 'jsonrpc', 'http-json'].includes(update.preferredTransport)) {
32
+ throw new ControlPlaneError(400, 'preferredTransport must be auto, jsonrpc, or http-json');
33
+ }
34
+ }
35
+ export function validateAgentId(value) {
36
+ const id = decodeURIComponent(value).trim().toLowerCase();
37
+ if (!/^[a-z0-9][a-z0-9._-]{0,63}$/.test(id)) {
38
+ throw new ControlPlaneError(400, 'Invalid Agent ID');
39
+ }
40
+ return id;
41
+ }
42
+ export function validateOpaqueId(value, label) {
43
+ const id = decodeURIComponent(value).trim();
44
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/.test(id)) {
45
+ throw new ControlPlaneError(400, `Invalid ${label} ID`);
46
+ }
47
+ return id;
48
+ }
49
+ export function validatePassword(value, confirmation) {
50
+ if (value !== confirmation) {
51
+ throw new ControlPlaneError(400, 'Console Password confirmation does not match');
52
+ }
53
+ try {
54
+ return validateAdminPassword(value);
55
+ }
56
+ catch (error) {
57
+ throw new ControlPlaneError(400, errorMessage(error));
58
+ }
59
+ }
60
+ export function validateKeyName(value) {
61
+ const name = cleanString(value);
62
+ if (!name)
63
+ throw new ControlPlaneError(400, 'API Key name is required');
64
+ if (name.length > 80)
65
+ throw new ControlPlaneError(400, 'API Key name is too long');
66
+ return name;
67
+ }
68
+ export function validateApiKeySecret(value) {
69
+ const secret = cleanString(value);
70
+ if (secret.length < 16) {
71
+ throw new ControlPlaneError(400, 'Custom API Key must contain at least 16 characters');
72
+ }
73
+ if (Buffer.byteLength(secret, 'utf8') > 512) {
74
+ throw new ControlPlaneError(400, 'Custom API Key must not exceed 512 bytes');
75
+ }
76
+ if (/^env:/i.test(secret) || /[\u0000-\u001f\u007f]/.test(secret)) {
77
+ throw new ControlPlaneError(400, 'Custom API Key contains an unsupported value');
78
+ }
79
+ return secret;
80
+ }
81
+ export function validateA2ASecret(value) {
82
+ const secret = cleanString(value);
83
+ if (!secret)
84
+ return '';
85
+ if (/^env:/i.test(secret) ||
86
+ Buffer.byteLength(secret, 'utf8') > 4096 ||
87
+ /[\u0000\r\n]/.test(secret)) {
88
+ throw new ControlPlaneError(400, 'A2A authentication value is invalid');
89
+ }
90
+ return secret;
91
+ }
92
+ export function validateAgentUrl(value) {
93
+ let url;
94
+ try {
95
+ url = new URL(value);
96
+ }
97
+ catch {
98
+ throw new ControlPlaneError(400, 'A2A Agent Card URL is invalid');
99
+ }
100
+ if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.hash) {
101
+ throw new ControlPlaneError(400, 'A2A Agent Card URL must use http(s) without credentials or a fragment');
102
+ }
103
+ return url.toString().replace(/\/$/, '');
104
+ }
105
+ export function defaultAgentCardUrl(agentUrl) {
106
+ if (!agentUrl)
107
+ return undefined;
108
+ return new URL('/.well-known/agent-card.json', agentUrl).toString();
109
+ }
110
+ export function clampTimeout(value, fallback, min, max) {
111
+ if (value === undefined)
112
+ return fallback;
113
+ if (!Number.isInteger(value) || value < min || value > max) {
114
+ throw new ControlPlaneError(400, `timeout must be between ${min} and ${max}`);
115
+ }
116
+ return value;
117
+ }
118
+ export function preservedAcpAdvanced(previous) {
119
+ const result = {};
120
+ for (const key of ['command', 'args', 'probeArgs', 'inheritEnv', 'env']) {
121
+ if (previous[key] !== undefined)
122
+ result[key] = structuredClone(previous[key]);
123
+ }
124
+ return result;
125
+ }
126
+ export function setOptionalString(target, key, value) {
127
+ const text = cleanString(value);
128
+ if (text)
129
+ target[key] = text;
130
+ else
131
+ delete target[key];
132
+ }
133
+ export function validHeaderName(value) {
134
+ return /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(value);
135
+ }
136
+ export function safeSecretEqual(left, right) {
137
+ const leftBuffer = Buffer.from(left);
138
+ const rightBuffer = Buffer.from(right);
139
+ return leftBuffer.length === rightBuffer.length && timingSafeEqual(leftBuffer, rightBuffer);
140
+ }
141
+ export function cleanString(value) {
142
+ return typeof value === 'string' ? value.trim() : '';
143
+ }
144
+ export function recordValue(value) {
145
+ return isRecord(value) ? { ...value } : {};
146
+ }
147
+ export function isRecord(value) {
148
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
149
+ }
150
+ export function errorMessage(error) {
151
+ return error instanceof Error ? error.message : String(error);
152
+ }
@@ -1,39 +1,20 @@
1
+ import { type AgentdAgentUpdate, type AgentdApiKeyUpdate, type AgentdRuntimeSettingsUpdate } from './control-plane-validation.js';
2
+ export { ControlPlaneError, type AgentdAgentUpdate, type AgentdApiKeyUpdate, type AgentdRuntimeSettingsUpdate } from './control-plane-validation.js';
1
3
  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
- }
4
+ import { type AgentdApiKeyPrincipal, type AgentdApiKeyScope, type AgentdApiKeyView, type AgentdConfig, type AgentdControlPlaneView } from './types.js';
30
5
  export declare class AgentdControlPlane {
31
6
  private readonly configPath;
32
7
  private config;
33
8
  private readonly sessions;
9
+ /** Process-local proof, delivered only through the local CLI / embedding API. */
10
+ setupToken?: string;
34
11
  private queue;
35
12
  private usageTimer?;
13
+ private readonly keyWatchers;
14
+ /** Observe authorization without updating last-used time or retaining a stale scope. */
15
+ watchApiKey(keyId: string, secret: string, agentId: string, revoked: () => void): () => void;
36
16
  constructor(configPath: string, config: AgentdConfig, sessions: SessionManager);
17
+ verifySetupToken(token: string): boolean;
37
18
  snapshot(): AgentdControlPlaneView;
38
19
  isInitialized(): boolean;
39
20
  needsAdminSetup(): boolean;
@@ -85,7 +66,3 @@ export declare class AgentdControlPlane {
85
66
  private agentView;
86
67
  private exclusive;
87
68
  }
88
- export declare class ControlPlaneError extends Error {
89
- readonly status: number;
90
- constructor(status: number, message: string);
91
- }