@alfe.ai/claude-code-host 0.1.5 → 0.1.7

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/dist/index.d.cts CHANGED
@@ -5,40 +5,117 @@ import { spawn } from "node:child_process";
5
5
 
6
6
  //# sourceMappingURL=tool-error-capture.d.ts.map
7
7
  //#endregion
8
- //#region src/index.d.ts
8
+ //#region src/transport.d.ts
9
+ /**
10
+ * Shared HTTP transport for the Agent API client — request core, retry
11
+ * policy, error formatting, and the `ApiBase` class the domain method
12
+ * groups under `./domains/` build on.
13
+ */
9
14
  interface AgentApiClientConfig {
10
15
  apiKey: string;
11
16
  apiUrl: string;
12
17
  }
13
18
  /**
14
- * The broad-news providers behind the metered `services/news` Lambda. The
15
- * server validates this with a zod enum; a value outside the union is an
16
- * unpriceable product, so keep the literal union in lockstep with the service.
19
+ * Encode each path segment but keep the `/` separators — `encodeURIComponent`
20
+ * would escape the slashes too, breaking greedy proxy routes.
17
21
  */
18
- type NewsProvider = "apitube" | "newsdata";
19
- /** One normalized article. `sentiment` is provider-shaped (APITube supplies it). */
20
- interface NewsArticle {
21
- title: string;
22
- url: string;
23
- source: string;
24
- publishedAt: string;
25
- snippet: string;
26
- sentiment?: unknown;
22
+
23
+ declare class AgentApiTransport {
24
+ private readonly apiKey;
25
+ private readonly apiUrl;
26
+ constructor(config: AgentApiClientConfig);
27
+ /**
28
+ * Binary sibling of `request<T>()`. `request()` forces
29
+ * `Content-Type: application/json` and parses a `{ data: T }` envelope,
30
+ * neither of which fits a raw-audio flow (voice TTS/STT), so those go
31
+ * through this instead. Auth (Bearer), the request budget, and the single
32
+ * retry policy on transient 5xx / network errors is kept in sync with
33
+ * `request()`. Safe read methods retry once by default; mutation methods do
34
+ * not, because a response can be lost after a handler or provider call has
35
+ * already succeeded.
36
+ */
37
+ rawRequest(path: string, init: {
38
+ method: string;
39
+ headers: Headers;
40
+ body?: BodyInit | Uint8Array;
41
+ }, extra?: {
42
+ retry?: boolean;
43
+ }): Promise<Response>;
44
+ /**
45
+ * @param extra.timeoutMs Per-request abort timeout (default REQUEST_TIMEOUT_MS).
46
+ * Long endpoints (image generation) pass a larger value so the gateway's
47
+ * own timeout wins with a readable status instead of a client-side abort.
48
+ * @param extra.retry Whether to retry once on transient failures. Safe reads
49
+ * (GET/HEAD/OPTIONS) default to true; mutations default to false. Set true
50
+ * only when the endpoint's server-side contract is explicitly idempotent.
51
+ * @param extra.signal Optional caller cancellation combined with the client's
52
+ * own timeout budget. Aborting either signal cancels the request.
53
+ */
54
+ request<T>(path: string, options?: RequestInit, extra?: {
55
+ timeoutMs?: number;
56
+ retry?: boolean;
57
+ signal?: AbortSignal;
58
+ }): Promise<T>;
27
59
  }
28
- /** Provider-agnostic result — the server normalizes every adapter to this. */
29
- interface NewsResult {
30
- articles: NewsArticle[];
31
- provider: string;
60
+ /**
61
+ * Base class for the domain method groups. Holds the shared transport;
62
+ * `AgentApiClient` assembles the groups onto one class via `applyMixins`
63
+ * (prototype copy), so methods keep their original `this`-on-the-client
64
+ * call shape.
65
+ */
66
+ declare class ApiBase {
67
+ protected readonly transport: AgentApiTransport;
68
+ constructor(transport: AgentApiTransport);
32
69
  }
33
- interface RemoteSessionInfo {
34
- sessionId: string;
35
- agentId: string;
36
- surface: "browser" | "terminal";
37
- status: "agent_driving" | "awaiting_human" | "human_in_control" | "resuming" | "completed" | "expired" | "failed";
38
- url?: string;
39
- instructions?: string;
40
- requestedAt?: string;
70
+ //# sourceMappingURL=transport.d.ts.map
71
+ //#endregion
72
+ //#region src/domains/workspace.d.ts
73
+ /** Response of GET /agent/workspace (services/agents). */
74
+ interface AgentWorkspaceInfo {
75
+ templateKey?: string;
76
+ defaultModel?: string;
77
+ installedFrom?: {
78
+ templateKey: string;
79
+ authorTenantId: string;
80
+ version: number;
81
+ };
82
+ runtime?: string;
83
+ teams?: {
84
+ teamId: string;
85
+ name: string;
86
+ description?: string;
87
+ parentTeamId?: string;
88
+ }[];
89
+ projects?: {
90
+ projectId: string;
91
+ name: string;
92
+ description?: string;
93
+ status: string;
94
+ parentProjectId?: string;
95
+ }[];
96
+ teamIds?: string[];
97
+ projectIds?: string[];
98
+ }
99
+ declare class WorkspaceApi extends ApiBase {
100
+ /**
101
+ * GET /agent/workspace — workspace config for the authenticated agent
102
+ * (template assignment, default model, org roster).
103
+ */
104
+ getWorkspace(): Promise<AgentWorkspaceInfo>;
105
+ /**
106
+ * GET /templates/{key}/files — persona/workspace file contents for a
107
+ * template the agent has access to. Pass `version` to pin to the version
108
+ * the agent was installed from (omit → the endpoint resolves `latest`).
109
+ */
110
+ getTemplateFiles(templateKey: string, opts?: {
111
+ version?: number;
112
+ }): Promise<{
113
+ files: Record<string, string>;
114
+ }>;
41
115
  }
116
+ //# sourceMappingURL=workspace.d.ts.map
117
+ //#endregion
118
+ //#region src/domains/sync.d.ts
42
119
  interface SyncAgentInfo {
43
120
  agentId: string;
44
121
  tenantId: string;
@@ -123,6 +200,65 @@ interface SharedFileEntry {
123
200
  size: number;
124
201
  contentType?: string;
125
202
  }
203
+ declare class SyncApi extends ApiBase {
204
+ syncRegister(args?: {
205
+ displayName?: string;
206
+ }): Promise<{
207
+ agent: SyncAgentInfo;
208
+ }>;
209
+ syncGetManifest(): Promise<SyncManifest>;
210
+ syncPresign(args: {
211
+ files: {
212
+ path: string;
213
+ operation: "put" | "get";
214
+ contentType?: string;
215
+ }[];
216
+ }): Promise<{
217
+ urls: SyncPresignedUrl[];
218
+ }>;
219
+ syncConfirmUpload(args: {
220
+ filePath: string;
221
+ hash: string;
222
+ size: number;
223
+ storageClass?: "STANDARD" | "GLACIER_IR";
224
+ }): Promise<SyncConfirmedUpload>;
225
+ syncReconstruct(args: {
226
+ mode: "full" | "active" | "memory";
227
+ }): Promise<SyncReconstructBundle>;
228
+ syncGetStats(): Promise<SyncAgentStats>;
229
+ syncListFiles(args?: {
230
+ prefix?: string;
231
+ }): Promise<{
232
+ files: SyncFileEntry[];
233
+ }>;
234
+ syncListSessions(): Promise<{
235
+ sessions: SyncSessionEntry[];
236
+ }>;
237
+ syncGetSession(sessionId: string): Promise<SyncSessionContent>;
238
+ syncDeleteFile(filePath: string): Promise<{
239
+ removed: boolean;
240
+ }>;
241
+ sharedListFiles(args: {
242
+ scope: "org" | "team" | "project";
243
+ scopeId: string;
244
+ limit?: number;
245
+ cursor?: string;
246
+ }): Promise<{
247
+ files: SharedFileEntry[];
248
+ nextCursor: string | null;
249
+ }>;
250
+ sharedDownloadUrl(args: {
251
+ scope: "org" | "team" | "project";
252
+ scopeId: string;
253
+ filePath: string;
254
+ }): Promise<{
255
+ downloadUrl: string;
256
+ expiresIn: number;
257
+ }>;
258
+ }
259
+ //# sourceMappingURL=sync.d.ts.map
260
+ //#endregion
261
+ //#region src/domains/knowledge.d.ts
126
262
  type KnowledgeScopeType = "org" | "team" | "project";
127
263
  interface KnowledgeScope {
128
264
  scopeType: KnowledgeScopeType;
@@ -165,15 +301,6 @@ interface KnowledgeProfile {
165
301
  updatedAt: string | null;
166
302
  updatedBy: string | null;
167
303
  }
168
- interface KnowledgeDoc {
169
- filePath: string;
170
- fileName: string;
171
- contentType?: string;
172
- size: number;
173
- uploadedBy?: string;
174
- createdAt: string;
175
- updatedAt: string;
176
- }
177
304
  type ChangeRequestResourceType = "doc" | "profile";
178
305
  type ChangeRequestOperation = "create" | "update" | "delete";
179
306
  type ChangeRequestStatus = "open" | "approved" | "rejected" | "withdrawn" | "superseded";
@@ -215,6 +342,200 @@ interface ProposeScopeChangeInput {
215
342
  /** profile: the proposed value ({ about, description, links }). */
216
343
  proposedValue?: unknown;
217
344
  }
345
+ interface KnowledgeDoc {
346
+ filePath: string;
347
+ fileName: string;
348
+ contentType?: string;
349
+ size: number;
350
+ uploadedBy?: string;
351
+ createdAt: string;
352
+ updatedAt: string;
353
+ }
354
+ declare class KnowledgeApi extends ApiBase {
355
+ /**
356
+ * Semantic search across the agent's member scopes. Fan-out is gated
357
+ * server-side by `listScopes` set-inclusion (fail-closed). Pass
358
+ * `scopeType` + `scopeId` to narrow to one scope; a non-member scope
359
+ * yields empty results (never a cross-scope leak).
360
+ */
361
+ knowledgeSearch(query: string, opts?: {
362
+ limit?: number;
363
+ scopeType?: KnowledgeScopeType;
364
+ scopeId?: string;
365
+ }): Promise<KnowledgeSearchResult>;
366
+ /** Enumerate the scopes (org + teams + projects) this agent belongs to. */
367
+ listScopes(): Promise<{
368
+ scopes: KnowledgeScope[];
369
+ }>;
370
+ /** Read a scope's structured knowledge profile (after membership check). */
371
+ getScopeProfile(scopeType: KnowledgeScopeType, scopeId: string): Promise<KnowledgeProfile>;
372
+ /**
373
+ * Open a change request against a scope's knowledge resource. For a doc
374
+ * create/update, `services/org` returns a presigned staging PUT; this method
375
+ * uploads the proposed `content` to it (echoing the same Content-Type that
376
+ * was signed), mirroring `writeScopeDoc`. The staged body is applied to the
377
+ * canonical doc — attributed to this agent — only when a reviewer approves.
378
+ */
379
+ proposeScopeChange(scopeType: KnowledgeScopeType, scopeId: string, input: ProposeScopeChangeInput): Promise<KnowledgeChangeRequest>;
380
+ /**
381
+ * List the agent's OWN change requests in a scope (filtered server-side to
382
+ * this agent as proposer). Pass `status` to narrow to open / approved / etc.
383
+ */
384
+ listScopeChangeRequests(scopeType: KnowledgeScopeType, scopeId: string, opts?: {
385
+ status?: ChangeRequestStatus;
386
+ limit?: number;
387
+ cursor?: string;
388
+ }): Promise<{
389
+ changeRequests: KnowledgeChangeRequest[];
390
+ nextCursor: string | null;
391
+ }>;
392
+ /** List a scope's docs (the org-files corpus; mirrored to shared/<scope>/). */
393
+ listScopeDocs(scopeType: KnowledgeScopeType, scopeId: string, opts?: {
394
+ limit?: number;
395
+ cursor?: string;
396
+ }): Promise<{
397
+ files: KnowledgeDoc[];
398
+ nextCursor: string | null;
399
+ }>;
400
+ /**
401
+ * Read the full text of a scope doc. Resolves a presigned download URL
402
+ * from `services/org`, then fetches the bytes directly from S3 (the one
403
+ * legitimate raw fetch in a plugin — same pattern as sync).
404
+ */
405
+ readScopeDoc(scopeType: KnowledgeScopeType, scopeId: string, filePath: string, opts?: {
406
+ maxBytes?: number;
407
+ }): Promise<{
408
+ filePath: string;
409
+ text: string;
410
+ }>;
411
+ /**
412
+ * Write (create or overwrite) a scope doc. Two-step presigned upload:
413
+ * `services/org` returns a signed URL plus `requiredHeaders` (author /
414
+ * authorKind / message as `x-amz-meta-*`) that MUST be sent verbatim on
415
+ * the PUT, alongside the same `Content-Type` that was signed. Author and
416
+ * authorKind are server-set from the agent token — never trusted here.
417
+ */
418
+ writeScopeDoc(scopeType: KnowledgeScopeType, scopeId: string, filePath: string, content: string, opts?: {
419
+ contentType?: string;
420
+ message?: string;
421
+ }): Promise<{
422
+ filePath: string;
423
+ }>;
424
+ }
425
+ //# sourceMappingURL=knowledge.d.ts.map
426
+ //#endregion
427
+ //#region src/domains/mobile.d.ts
428
+ /** Response of GET /mobile/numbers for an agent (services/mobile). */
429
+ interface MobileNumberInfo {
430
+ phoneNumber: string;
431
+ countryCode: string;
432
+ monthlyPrice?: number;
433
+ status: string;
434
+ errorMessage?: string;
435
+ }
436
+ /** One purchasable number from GET /mobile/numbers/search. */
437
+ interface MobileAvailableNumber {
438
+ number: string;
439
+ friendlyName: string;
440
+ locality: string;
441
+ region: string;
442
+ country: string;
443
+ }
444
+ /** Approved WhatsApp content template from GET /mobile/whatsapp/templates. */
445
+ interface WhatsAppTemplate {
446
+ contentSid: string;
447
+ name: string;
448
+ language: string;
449
+ body: string;
450
+ variables: Record<string, string>;
451
+ category?: string;
452
+ }
453
+ declare class MobileApi extends ApiBase {
454
+ getMobileNumber(): Promise<MobileNumberInfo>;
455
+ searchMobileNumbers(args?: {
456
+ country?: string;
457
+ query?: string;
458
+ }): Promise<{
459
+ numbers: MobileAvailableNumber[];
460
+ monthlyPrice: number;
461
+ }>;
462
+ assignMobileNumber(args: {
463
+ phoneNumber: string;
464
+ countryCode: string;
465
+ }): Promise<{
466
+ phoneNumber: string;
467
+ countryCode: string;
468
+ status: "pending";
469
+ }>;
470
+ releaseMobileNumber(): Promise<{
471
+ released: true;
472
+ }>;
473
+ sendSms(args: {
474
+ to: string;
475
+ body: string;
476
+ }): Promise<{
477
+ sent: true;
478
+ sid: string;
479
+ }>;
480
+ startOutboundCall(args: {
481
+ to: string;
482
+ }): Promise<{
483
+ callSid: string;
484
+ status: string;
485
+ }>;
486
+ getWhatsAppSession(to: string): Promise<{
487
+ active: boolean;
488
+ expiresAt?: string;
489
+ }>;
490
+ sendWhatsAppMessage(args: {
491
+ to: string;
492
+ body: string;
493
+ }): Promise<{
494
+ sent: true;
495
+ sid: string;
496
+ }>;
497
+ sendWhatsAppTemplate(args: {
498
+ to: string;
499
+ contentSid: string;
500
+ contentVariables: Record<string, string>;
501
+ bodyPreview?: string;
502
+ }): Promise<{
503
+ sent: true;
504
+ sid: string;
505
+ }>;
506
+ listWhatsAppTemplates(): Promise<{
507
+ templates: WhatsAppTemplate[];
508
+ }>;
509
+ }
510
+ //# sourceMappingURL=mobile.d.ts.map
511
+ //#endregion
512
+ //#region src/domains/remote.d.ts
513
+ interface RemoteSessionInfo {
514
+ sessionId: string;
515
+ agentId: string;
516
+ surface: "browser" | "terminal";
517
+ status: "agent_driving" | "awaiting_human" | "human_in_control" | "resuming" | "completed" | "expired" | "failed";
518
+ url?: string;
519
+ instructions?: string;
520
+ requestedAt?: string;
521
+ }
522
+ declare class RemoteApi extends ApiBase {
523
+ requestBrowserTakeover(args: {
524
+ instructions: string;
525
+ url?: string;
526
+ conversationId?: string;
527
+ }): Promise<{
528
+ sessionId: string;
529
+ status: string;
530
+ }>;
531
+ getRemoteSession(sessionId: string): Promise<RemoteSessionInfo>;
532
+ completeRemoteSession(sessionId: string): Promise<{
533
+ ok: boolean;
534
+ }>;
535
+ }
536
+ //# sourceMappingURL=remote.d.ts.map
537
+ //#endregion
538
+ //#region src/domains/self.d.ts
218
539
  /** Voice settings — core agent config. Mirrors `VoiceConfig` in `@alfe/types`. */
219
540
  interface AgentVoiceConfig {
220
541
  /** ElevenLabs voice ID; platform default when unset. */
@@ -256,11 +577,50 @@ interface AgentVoice {
256
577
  labels: Record<string, string>;
257
578
  category: string;
258
579
  }
259
- /** The ElevenLabs models with a pricing row — the TTS endpoint rejects any other value. */
260
- type VoiceTtsModel = "eleven_turbo_v2_5" | "eleven_multilingual_v2";
261
- interface VoiceTtsArgs {
262
- /** Text to synthesize (1–5000 chars — the endpoint enforces this). */
263
- text: string;
580
+ declare class SelfApi extends ApiBase {
581
+ /** Update the agent's own name and/or voice config. Returns the updated agent. */
582
+ updateSelf(update: {
583
+ name?: string;
584
+ voiceConfig?: AgentVoiceConfig;
585
+ }): Promise<AgentSelf>;
586
+ /**
587
+ * Generate the agent's own avatar from a text prompt. The image is generated,
588
+ * stored, and set on the agent server-side; returns the updated agent.
589
+ *
590
+ * ASYNC (same reason as `generateImage`): avatar gen runs `gpt-image-1`
591
+ * (30–60s) which exceeds the API Gateway 30s ceiling, so this enqueues a job
592
+ * (`POST /agent/avatar/generate` → `jobId`) then polls (`GET /agent/avatar/{jobId}`)
593
+ * until the avatar is set. Signature unchanged — the plugin is unaffected.
594
+ */
595
+ generateAvatar(args: {
596
+ prompt: string;
597
+ }): Promise<AgentSelf>;
598
+ /**
599
+ * Get a presigned PUT URL to upload a new avatar image. Upload the bytes to
600
+ * `uploadUrl`, then call `finalizeAvatar(s3Key)` to set it on the agent.
601
+ */
602
+ presignAvatar(args: {
603
+ mimeType: string;
604
+ size: number;
605
+ }): Promise<AgentAvatarPresign>;
606
+ /**
607
+ * Finalize an avatar upload — validates ownership + size, then sets the
608
+ * agent's `avatarUrl` server-side. Returns the updated agent.
609
+ */
610
+ finalizeAvatar(s3Key: string): Promise<AgentSelf>;
611
+ /** List the platform voice catalogue (ElevenLabs) so the agent can pick its own voice. */
612
+ listVoices(): Promise<{
613
+ voices: AgentVoice[];
614
+ }>;
615
+ }
616
+ //# sourceMappingURL=self.d.ts.map
617
+ //#endregion
618
+ //#region src/domains/voice.d.ts
619
+ /** The ElevenLabs models with a pricing row — the TTS endpoint rejects any other value. */
620
+ type VoiceTtsModel = "eleven_turbo_v2_5" | "eleven_multilingual_v2";
621
+ interface VoiceTtsArgs {
622
+ /** Text to synthesize (1–5000 chars — the endpoint enforces this). */
623
+ text: string;
264
624
  /** ElevenLabs voice id; platform default when unset. */
265
625
  voiceId?: string;
266
626
  /** TTS model; `eleven_turbo_v2_5` (lower latency) when unset. */
@@ -288,84 +648,161 @@ interface VoiceSttResult {
288
648
  /** Deepgram confidence in (0,1]. */
289
649
  confidence: number;
290
650
  }
291
- declare class AgentApiClient {
292
- private readonly apiKey;
293
- private readonly apiUrl;
294
- constructor(config: AgentApiClientConfig);
295
- private request;
296
- syncRegister(args?: {
297
- displayName?: string;
298
- }): Promise<{
299
- agent: SyncAgentInfo;
300
- }>;
301
- syncGetManifest(): Promise<SyncManifest>;
302
- syncPresign(args: {
303
- files: {
304
- path: string;
305
- operation: "put" | "get";
306
- contentType?: string;
307
- }[];
308
- }): Promise<{
309
- urls: SyncPresignedUrl[];
310
- }>;
311
- syncConfirmUpload(args: {
312
- filePath: string;
313
- hash: string;
651
+ declare class VoiceApi extends ApiBase {
652
+ /**
653
+ * Text-to-speech. Returns raw PCM audio bytes plus their framing — the
654
+ * voice service defaults to 24 kHz / mono / 16-bit. Wrap in a WAV container
655
+ * to produce a playable file. Metered per character against the tenant
656
+ * credit pool server-side; TTS completes regardless of metering outcome.
657
+ */
658
+ tts(args: VoiceTtsArgs): Promise<VoiceTtsResult>;
659
+ /**
660
+ * Speech-to-text. Accepts raw linear16 (16-bit LE) mono PCM — NOT a WAV or
661
+ * other container (the endpoint transcribes with a fixed linear16 encoding,
662
+ * so a container header would be transcribed as noise). Strip any WAV header
663
+ * and pass `sampleRate` from it before calling. Metered by transcribed
664
+ * duration against the tenant credit pool server-side.
665
+ */
666
+ stt(args: VoiceSttArgs): Promise<VoiceSttResult>;
667
+ }
668
+ //# sourceMappingURL=voice.d.ts.map
669
+ //#endregion
670
+ //#region src/domains/search.d.ts
671
+ /**
672
+ * The broad-news providers behind the metered `services/news` Lambda. The
673
+ * server validates this with a zod enum; a value outside the union is an
674
+ * unpriceable product, so keep the literal union in lockstep with the service.
675
+ */
676
+ type NewsProvider = "apitube" | "newsdata";
677
+ /** One normalized article. `sentiment` is provider-shaped (APITube supplies it). */
678
+ interface NewsArticle {
679
+ title: string;
680
+ url: string;
681
+ source: string;
682
+ publishedAt: string;
683
+ snippet: string;
684
+ sentiment?: unknown;
685
+ }
686
+ /** Provider-agnostic result — the server normalizes every adapter to this. */
687
+ interface NewsResult {
688
+ articles: NewsArticle[];
689
+ provider: string;
690
+ }
691
+ declare class SearchApi extends ApiBase {
692
+ searchWeb(params: {
693
+ query: string;
694
+ count?: number;
695
+ offset?: number;
696
+ country?: string;
697
+ freshness?: string;
698
+ }, options?: {
699
+ signal?: AbortSignal;
700
+ }): Promise<unknown>;
701
+ searchImages(params: {
702
+ query: string;
703
+ count?: number;
704
+ }, options?: {
705
+ signal?: AbortSignal;
706
+ }): Promise<unknown>;
707
+ searchNews(params: {
708
+ query: string;
709
+ count?: number;
710
+ offset?: number;
711
+ freshness?: string;
712
+ }, options?: {
713
+ signal?: AbortSignal;
714
+ }): Promise<unknown>;
715
+ /** Search news across the selected provider's corpus. → POST /agent/news/search */
716
+ newsSearch(params: {
717
+ query: string;
718
+ provider?: NewsProvider;
719
+ source?: string;
720
+ from?: string;
721
+ to?: string;
722
+ language?: string;
723
+ category?: string;
724
+ limit?: number;
725
+ }): Promise<NewsResult>;
726
+ /** Top headlines for the selected provider. → POST /agent/news/headlines */
727
+ newsHeadlines(params?: {
728
+ provider?: NewsProvider;
729
+ category?: string;
730
+ source?: string;
731
+ language?: string;
732
+ limit?: number;
733
+ }): Promise<NewsResult>;
734
+ }
735
+ //# sourceMappingURL=search.d.ts.map
736
+ //#endregion
737
+ //#region src/domains/webhooks.d.ts
738
+ interface AgentWebhook {
739
+ webhookId: string;
740
+ tenantId: string;
741
+ agentId: string;
742
+ name: string;
743
+ provider: string;
744
+ active: boolean;
745
+ createdBy: string;
746
+ createdAt: string;
747
+ updatedAt: string;
748
+ }
749
+ interface CreatedAgentWebhook extends AgentWebhook {
750
+ url: string;
751
+ signingSecret: string;
752
+ }
753
+ interface AgentWebhookDelivery {
754
+ deliveryId: string;
755
+ webhookId: string;
756
+ status: string;
757
+ attempts: number;
758
+ createdAt: string;
759
+ deliveredAt?: string;
760
+ }
761
+ declare class WebhooksApi extends ApiBase {
762
+ createWebhook(args: {
763
+ name: string;
764
+ provider?: "generic" | "github" | "stripe" | "slack";
765
+ }): Promise<CreatedAgentWebhook>;
766
+ listWebhooks(): Promise<AgentWebhook[]>;
767
+ deleteWebhook(webhookId: string): Promise<{
768
+ webhookId: string;
769
+ active: false;
770
+ }>;
771
+ rotateWebhookSecret(webhookId: string): Promise<{
772
+ webhookId: string;
773
+ signingSecret: string;
774
+ }>;
775
+ listWebhookDeliveries(webhookId: string): Promise<AgentWebhookDelivery[]>;
776
+ }
777
+ //# sourceMappingURL=webhooks.d.ts.map
778
+ //#endregion
779
+ //#region src/domains/chat.d.ts
780
+ declare class ChatApi extends ApiBase {
781
+ presignAttachments(files: {
782
+ filename: string;
783
+ mimeType: string;
314
784
  size: number;
315
- storageClass?: "STANDARD" | "GLACIER_IR";
316
- }): Promise<SyncConfirmedUpload>;
317
- syncReconstruct(args: {
318
- mode: "full" | "active" | "memory";
319
- }): Promise<SyncReconstructBundle>;
320
- syncGetStats(): Promise<SyncAgentStats>;
321
- syncListFiles(args?: {
322
- prefix?: string;
323
- }): Promise<{
324
- files: SyncFileEntry[];
325
- }>;
326
- syncListSessions(): Promise<{
327
- sessions: SyncSessionEntry[];
328
- }>;
329
- syncGetSession(sessionId: string): Promise<SyncSessionContent>;
330
- syncDeleteFile(filePath: string): Promise<{
331
- removed: boolean;
332
- }>;
333
- sharedListFiles(args: {
334
- scope: "org" | "team" | "project";
335
- scopeId: string;
336
- }): Promise<{
337
- files: SharedFileEntry[];
338
- nextCursor: string | null;
785
+ }[]): Promise<{
786
+ attachments: {
787
+ id: string;
788
+ uploadUrl: string;
789
+ downloadUrl: string;
790
+ s3Key: string;
791
+ expiresAt: string;
792
+ }[];
339
793
  }>;
340
- sharedDownloadUrl(args: {
341
- scope: "org" | "team" | "project";
342
- scopeId: string;
343
- filePath: string;
794
+ recordActivity(data: {
795
+ userId?: string;
796
+ channel: string;
797
+ role: "user" | "assistant";
344
798
  }): Promise<{
345
- downloadUrl: string;
346
- expiresIn: number;
347
- }>;
348
- listIntegrations(): Promise<IntegrationInstall[]>;
349
- getIntegrationConfig(integrationId: string): Promise<IntegrationConfigResult>;
350
- updateIntegrationConfig(integrationId: string, config: Record<string, unknown>): Promise<void>;
351
- installIntegration(integrationId: string, options?: {
352
- version?: string;
353
- config?: Record<string, unknown>;
354
- }): Promise<IntegrationInstall>;
355
- removeIntegration(integrationId: string): Promise<IntegrationInstall>;
356
- getOAuthUrl(provider: string, scopes?: string[]): Promise<{
357
- url: string;
358
- provider: string;
359
- expiresIn: number;
360
- }>;
361
- getOAuthStatus(provider: string): Promise<{
362
- provider: string;
363
- connected: boolean;
364
- config?: Record<string, string>;
365
- }>;
366
- getRegistry(): Promise<{
367
- integrations: RegistryEntry[];
799
+ recorded: boolean;
368
800
  }>;
801
+ }
802
+ //# sourceMappingURL=chat.d.ts.map
803
+ //#endregion
804
+ //#region src/domains/connect-credentials.d.ts
805
+ declare class ConnectCredentialsApi extends ApiBase {
369
806
  /**
370
807
  * Returns every connected Google account for the agent. Multi-account by
371
808
  * design — the openclaw-google plugin requires the LLM to pass `email`
@@ -422,82 +859,19 @@ declare class AgentApiClient {
422
859
  [key: string]: unknown;
423
860
  }>;
424
861
  /**
425
- * Resolve the primary cTrader Connection's credentials for the calling
426
- * agent. Unlike most providers, the cTrader Open API needs app-level auth
427
- * (`clientId` + `clientSecret`) AND account auth (`accessToken` +
428
- * `accountId`) on the socket, so `@alfe.ai/ctrader-mcp` self-fetches the
429
- * full set here at startup (the atlassian/google pattern). `clientId` /
430
- * `clientSecret` are the SST-sourced global app credentials the connect
431
- * endpoint injects — they are never persisted on the connection. `host` is
432
- * the resolved TLS endpoint (`live.ctraderapi.com` / `demo.ctraderapi.com`)
433
- * derived from the selected account's live/demo flag.
862
+ * @deprecated Returns a single primary credential blob (legacy "pick-the-
863
+ * default-connection" shape). Use `getGithubAccounts()` for the multi-
864
+ * account shape required by Pattern A — explicit selector args on every
865
+ * tool. Retained because the `@alfe.ai/github-mcp` proxy is the
866
+ * only consumer that knows about Pattern A; legacy env-interpolation
867
+ * callers will keep hitting `/credentials` until they move to the proxy.
434
868
  */
435
- getCTraderCredentials(): Promise<{
869
+ getGithubCredentials(): Promise<{
870
+ login: string;
436
871
  accessToken: string;
437
- refreshToken: string;
438
- accountId: string;
439
- host: string;
440
- clientId: string;
441
- clientSecret: string;
442
872
  }>;
443
873
  /**
444
- * Pattern A: multi-account credential fetch for cTrader.
445
- *
446
- * Unlike atlassian/salesforce (one Connection row per account/site), a
447
- * cTrader is MULTI-grant per agent: an agent may connect several distinct
448
- * cTrader logins, each its own Connection row keyed on `accountIdentifier =
449
- * ctid:<userId>` (Phase 1). This aggregates the *trading accounts* across
450
- * ALL of those Connection rows — each row contributes its `availableAccounts`
451
- * flattened, and every account carries ITS OWN grant's `accessToken` (the
452
- * token that authenticates that account against the cTrader Open API). One
453
- * OAuth grant still covers all accounts under that single login on one shared
454
- * token; only the `ctidTraderAccountId` and the protobuf socket `host` (live
455
- * vs demo) differ within a grant. Across grants the tokens differ, so the
456
- * token is now PER-ACCOUNT rather than hoisted to the top level.
457
- *
458
- * `host` per account is derived from the account's `isLive` flag
459
- * (`live.ctraderapi.com` / `demo.ctraderapi.com`) — the same mapping the
460
- * connect provider applies server-side when an account is auto-selected.
461
- *
462
- * `clientId` / `clientSecret` are the SST-sourced GLOBAL app credentials the
463
- * connect endpoint injects — identical across every Connection row (one
464
- * cTrader app), never persisted on a connection. We take them from the first
465
- * row that carries them.
466
- *
467
- * Accounts are deduped on `ctidTraderAccountId` first-wins: Spotware ids are
468
- * globally unique across logins, so a duplicate can only appear if the same
469
- * account somehow surfaced under two grants — first-wins keeps it
470
- * deterministic.
471
- *
472
- * `accounts` may be empty (no cTrader Connection at all), in which case we
473
- * return empty creds rather than throwing.
474
- */
475
- getCTraderAccounts(): Promise<{
476
- accounts: {
477
- ctidTraderAccountId: string;
478
- host: string;
479
- isLive: boolean;
480
- brokerName?: string;
481
- accountNumber?: string;
482
- accessToken: string;
483
- }[];
484
- clientId: string;
485
- clientSecret: string;
486
- }>;
487
- /**
488
- * @deprecated Returns a single primary credential blob (legacy "pick-the-
489
- * default-connection" shape). Use `getGithubAccounts()` for the multi-
490
- * account shape required by Pattern A — explicit selector args on every
491
- * tool. Retained because the `@alfe.ai/github-mcp` proxy is the
492
- * only consumer that knows about Pattern A; legacy env-interpolation
493
- * callers will keep hitting `/credentials` until they move to the proxy.
494
- */
495
- getGithubCredentials(): Promise<{
496
- login: string;
497
- accessToken: string;
498
- }>;
499
- /**
500
- * Pattern A: multi-account credential fetch for GitHub.
874
+ * Pattern A: multi-account credential fetch for GitHub.
501
875
  *
502
876
  * Returns every agent-scoped GitHub connection. The caller is expected
503
877
  * to require a `login` selector on every credential-touching tool and
@@ -521,67 +895,6 @@ declare class AgentApiClient {
521
895
  scopes: string;
522
896
  }[];
523
897
  }>;
524
- /**
525
- * Pattern A: provider-parameterized multi-account credential fetch for the
526
- * social connectors (Bluesky, and the approval-gated backlog: X, Meta,
527
- * Threads, LinkedIn, Pinterest, TikTok, Reddit, YouTube).
528
- *
529
- * Unlike the bespoke `getGithubAccounts()` / `getXeroAccounts()` shapes,
530
- * this returns a UNIFORM normalized account shape so `@alfe.ai/social-mcp`'s
531
- * shared driver can require a single `account` selector on every
532
- * credential-touching tool regardless of platform. The backend
533
- * `api-agents/{provider}/accounts` route is already provider-generic; this
534
- * is the client-side normalization the plan (`do-we-need-any-moonlit-toucan`
535
- * Phase 0, step 5) calls for.
536
- *
537
- * `accountIdentifier` is the stable per-account selector the LLM should
538
- * pass back (for Bluesky: the account DID). `accessToken` carries whatever
539
- * the provider's `buildCredentialsResponse` bundles (for Bluesky: the JSON
540
- * session bundle — the driver parses the `accessJwt` out of it, or reads the
541
- * top-level `accessJwt` from `providerMetadata`-adjacent fields). Everything
542
- * else the driver needs for routing (handle, pdsHost, did, …) is on
543
- * `providerMetadata`.
544
- *
545
- * Token refresh is delegated to connect (never done in-plugin) via the
546
- * per-account route `POST /agent/connect/{provider}/accounts/{accountIdentifier}/refresh`
547
- * — call `refreshSocialAccount(provider, accountIdentifier)`. (The non-account
548
- * `POST /agent/connect/{provider}/refresh` route refreshes the provider's
549
- * PRIMARY connection, which is wrong under multi-account Pattern A.)
550
- */
551
- getSocialAccounts(provider: string): Promise<{
552
- provider: string;
553
- accounts: {
554
- connectionId: string;
555
- accountIdentifier: string;
556
- displayName: string | null;
557
- accessToken: string;
558
- providerMetadata: Record<string, unknown>;
559
- connectedAt: string;
560
- }[];
561
- }>;
562
- /**
563
- * Pattern A: refresh a specific social Connection by its stable
564
- * `accountIdentifier` (for Bluesky: the account DID) via the
565
- * provider-generic per-account refresh route. The counterpart to
566
- * `getSocialAccounts(provider)`; `@alfe.ai/social-mcp` calls this on a
567
- * 401/ExpiredToken from the platform PDS/API, then re-fetches accounts to
568
- * pick up the rotated bundle.
569
- *
570
- * Refresh itself is ALWAYS delegated to connect — the plugin never calls
571
- * the platform's own refresh XRPC (e.g. `com.atproto.server.refreshSession`)
572
- * because connect owns the encrypted refresh token + rotation persistence
573
- * (Bluesky rotates the refreshJwt; a missed rotation kills the connection
574
- * after one refresh). The returned `accessToken` is whatever the provider's
575
- * `refreshToken` hook re-bundled (for Bluesky: the JSON session bundle with
576
- * the fresh `accessJwt`) — callers typically ignore it and re-fetch via
577
- * `getSocialAccounts` for a consistent shape.
578
- */
579
- refreshSocialAccount(provider: string, accountIdentifier: string): Promise<{
580
- accountIdentifier: string;
581
- accessToken: string;
582
- accessTokenExpiresAt: string;
583
- expiresAt: string;
584
- }>;
585
898
  /**
586
899
  * @deprecated Returns a single primary credential blob (legacy "pick-the-
587
900
  * default-connection" shape). Use `getXeroAccounts()` for the multi-
@@ -599,8 +912,9 @@ declare class AgentApiClient {
599
912
  * selector arg (e.g. `xeroTenantId`) on every credential-touching tool
600
913
  * and look up the matching account by that selector at dispatch time.
601
914
  *
602
- * Returned `accounts[i].accountIdentifier` is the Xero tenantId — the
603
- * stable cross-session identifier the LLM should pass.
915
+ * `xeroTenantId` is the model-facing organisation selector. The separate
916
+ * `accountIdentifier` is the Connect persistence key used for refresh and
917
+ * may be an email; never substitute one for the other.
604
918
  */
605
919
  getXeroAccounts(): Promise<{
606
920
  accounts: {
@@ -618,12 +932,12 @@ declare class AgentApiClient {
618
932
  expiresAt: string;
619
933
  }>;
620
934
  /**
621
- * Pattern A: refresh a specific Xero connection by its `accountIdentifier`
622
- * (the Xero `tenantId`). The legacy `refreshXeroToken()` only refreshes
623
- * the *primary* connection, which is wrong for multi-tenant Xero where
624
- * each tenant has its own non-interchangeable access token.
935
+ * Refresh a specific Xero Connection by its exact `accountIdentifier` from
936
+ * `getXeroAccounts()`. Do not substitute `xeroTenantId`: current Xero OAuth
937
+ * rows may use the account email as their persistence key even when a sole
938
+ * organisation tenant ID is available in provider metadata.
625
939
  */
626
- refreshXeroAccountToken(xeroTenantId: string): Promise<{
940
+ refreshXeroAccountToken(accountIdentifier: string): Promise<{
627
941
  accessToken: string;
628
942
  accessTokenExpiresAt: string;
629
943
  expiresAt: string;
@@ -778,6 +1092,21 @@ declare class AgentApiClient {
778
1092
  accessToken: string;
779
1093
  expiresAt: string;
780
1094
  }>;
1095
+ /**
1096
+ * Pattern A: refresh one MYOB Connection by its stable
1097
+ * `accountIdentifier` (the MYOB business id returned by
1098
+ * `getMYOBAccounts()`).
1099
+ *
1100
+ * MYOB refresh tokens belong to individual Connection rows. A
1101
+ * multi-business client must use this method instead of refreshing the
1102
+ * primary Connection and copying that access token into every cached
1103
+ * business client.
1104
+ */
1105
+ refreshMYOBAccountToken(accountIdentifier: string): Promise<{
1106
+ accessToken: string;
1107
+ accessTokenExpiresAt: string;
1108
+ expiresAt: string;
1109
+ }>;
781
1110
  /**
782
1111
  * @deprecated Returns a single primary credential blob. Use
783
1112
  * `getSalesforceAccounts()` for the multi-account shape required by
@@ -817,67 +1146,6 @@ declare class AgentApiClient {
817
1146
  accessTokenExpiresAt: string;
818
1147
  expiresAt: string;
819
1148
  }>;
820
- /**
821
- * @deprecated Returns a single primary credential blob. Use
822
- * `getShopifyAccounts()` for the multi-account shape required by Pattern A
823
- * (`@alfe.ai/shopify-mcp` keys per-shop on the myshopify domain).
824
- */
825
- getShopifyCredentials(): Promise<{
826
- accessToken: string;
827
- shopDomain: string;
828
- shopGid: string;
829
- shopName: string;
830
- apiVersion: string;
831
- }>;
832
- /**
833
- * Pattern A: multi-account credential fetch for Shopify. Returns every
834
- * agent-scoped Shopify Connection. One OAuth grant maps to one store, so the
835
- * stable per-call selector is the store's myshopify domain (`shopDomain`),
836
- * NOT `accountIdentifier` — the connect provider keys `accountIdentifier` on
837
- * the immutable shop GID (falling back to the domain), so `shopDomain` is the
838
- * value the LLM passes and the plugin routes on.
839
- *
840
- * Each entry is shaped by the connect provider's `buildCredentialsResponse`:
841
- * `{ accessToken, shopDomain, shopGid, shopName, apiVersion }` — offline
842
- * Shopify tokens never expire, so there is NO token / expiry field and no
843
- * refresh method (unlike Salesforce). The GraphQL Admin API authenticates
844
- * purely on `X-Shopify-Access-Token`; no client credentials are on the wire.
845
- */
846
- getShopifyAccounts(): Promise<{
847
- accounts: {
848
- connectionId: string;
849
- accountIdentifier: string;
850
- displayName: string | null;
851
- connectedAt: string;
852
- accessToken: string;
853
- shopDomain: string;
854
- shopGid: string;
855
- shopName: string;
856
- apiVersion: string;
857
- }[];
858
- }>;
859
- /**
860
- * Disconnects one connected Microsoft 365 account for the agent, by its
861
- * `accountIdentifier`. Hits the generic per-account disconnect route
862
- * (`DELETE /agent/connect/microsoft/accounts/{accountIdentifier}`), which
863
- * resolves across the agent's full effective scope chain and deletes the
864
- * matching Connection row. Returns the remaining accounts.
865
- *
866
- * IMPORTANT: pass the `accountIdentifier` from `getMicrosoftAccounts()`, NOT
867
- * a synthesised email. For Microsoft, `accountIdentifier` is the user's email
868
- * only when the Graph profile fetch succeeded at connect time; it falls back
869
- * to the Azure tenant id (`tid` claim) otherwise. The backend matches on
870
- * `accountIdentifier` exactly, so passing an email would 404 on those
871
- * fallback-identifier accounts. (This is why the param is not named `email`,
872
- * unlike `disconnectGoogleAccount` where the identifier is always the email.)
873
- */
874
- disconnectMicrosoftAccount(accountIdentifier: string): Promise<{
875
- accounts: {
876
- accountIdentifier: string;
877
- displayName?: string;
878
- connectedAt?: string;
879
- }[];
880
- }>;
881
1149
  /**
882
1150
  * Pattern A: multi-account credential fetch for Microsoft 365.
883
1151
  *
@@ -901,9 +1169,6 @@ declare class AgentApiClient {
901
1169
  connectedAt: string;
902
1170
  accessToken: string;
903
1171
  accessTokenExpiresAt: string;
904
- refreshToken: string;
905
- clientId: string;
906
- clientSecret: string;
907
1172
  email: string;
908
1173
  microsoftTenantId: string;
909
1174
  workspaceDomain: string;
@@ -928,242 +1193,213 @@ declare class AgentApiClient {
928
1193
  accessTokenExpiresAt: string;
929
1194
  expiresAt: string;
930
1195
  }>;
931
- getTeamsCredentials(): Promise<{
932
- agentId: string;
933
- tenantId: string;
934
- azureAppId: string;
935
- azureBotId: string;
936
- azureClientSecret: string;
937
- botDisplayName?: string;
938
- teamsTenantId?: string;
939
- serviceUrl?: string;
940
- }>;
941
- sendTeamsMessage(data: {
942
- conversationId: string;
943
- text?: string;
944
- adaptiveCard?: Record<string, unknown>;
945
- }): Promise<{
946
- ok: boolean;
947
- activityId: string;
948
- }>;
949
- listTeamsChannels(): Promise<{
950
- channels: {
951
- id: string;
952
- name: string;
953
- description?: string;
954
- }[];
955
- }>;
956
- presignAttachments(files: {
957
- filename: string;
958
- mimeType: string;
959
- size: number;
960
- }[]): Promise<{
961
- attachments: {
962
- id: string;
963
- uploadUrl: string;
964
- downloadUrl: string;
965
- s3Key: string;
966
- expiresAt: string;
967
- }[];
968
- }>;
969
1196
  /**
970
- * Generate an image from a text prompt and get back a STABLE, public URL
971
- * (served from the agent-assets CDN — it does not expire). Embed the returned
972
- * `imageUrl` in a reply as markdown to show it to the user.
1197
+ * Disconnects one connected Microsoft 365 account for the agent, by its
1198
+ * `accountIdentifier`. Hits the generic per-account disconnect route
1199
+ * (`DELETE /agent/connect/microsoft/accounts/{accountIdentifier}`), which
1200
+ * resolves across the agent's full effective scope chain and deletes the
1201
+ * matching Connection row. Returns the remaining accounts.
973
1202
  *
974
- * ASYNC: `gpt-image-1` routinely runs 30–60s, which exceeds the API Gateway
975
- * 30s ceiling, so this enqueues a job (`POST /agent/images/generate` →
976
- * `jobId`) then polls (`GET /agent/images/{jobId}`) until it completes. The
977
- * worker's real failure message (e.g. an unsupported `size`) surfaces via the
978
- * job's `error` field.
1203
+ * IMPORTANT: pass the `accountIdentifier` from `getMicrosoftAccounts()`, NOT
1204
+ * a synthesised email. For Microsoft, `accountIdentifier` is the user's email
1205
+ * only when the Graph profile fetch succeeded at connect time; it falls back
1206
+ * to the Azure tenant id (`tid` claim) otherwise. The backend matches on
1207
+ * `accountIdentifier` exactly, so passing an email would 404 on those
1208
+ * fallback-identifier accounts. (This is why the param is not named `email`,
1209
+ * unlike `disconnectGoogleAccount` where the identifier is always the email.)
979
1210
  */
980
- generateImage(args: {
981
- prompt: string;
982
- model?: string;
983
- size?: string;
984
- quality?: string;
985
- }): Promise<{
986
- imageUrl: string;
987
- model: string;
988
- }>;
989
- recordActivity(data: {
990
- userId?: string;
991
- channel: string;
992
- role: "user" | "assistant";
993
- }): Promise<{
994
- recorded: boolean;
1211
+ disconnectMicrosoftAccount(accountIdentifier: string): Promise<{
1212
+ accounts: {
1213
+ accountIdentifier: string;
1214
+ displayName?: string;
1215
+ connectedAt?: string;
1216
+ }[];
995
1217
  }>;
996
- /** Update the agent's own name and/or voice config. Returns the updated agent. */
997
- updateSelf(update: {
998
- name?: string;
999
- voiceConfig?: AgentVoiceConfig;
1000
- }): Promise<AgentSelf>;
1001
- /**
1002
- * Generate the agent's own avatar from a text prompt. The image is generated,
1003
- * stored, and set on the agent server-side; returns the updated agent.
1004
- *
1005
- * ASYNC (same reason as `generateImage`): avatar gen runs `gpt-image-1`
1006
- * (30–60s) which exceeds the API Gateway 30s ceiling, so this enqueues a job
1007
- * (`POST /agent/avatar/generate` → `jobId`) then polls (`GET /agent/avatar/{jobId}`)
1008
- * until the avatar is set. Signature unchanged — the plugin is unaffected.
1009
- */
1010
- generateAvatar(args: {
1011
- prompt: string;
1012
- }): Promise<AgentSelf>;
1013
1218
  /**
1014
- * Get a presigned PUT URL to upload a new avatar image. Upload the bytes to
1015
- * `uploadUrl`, then call `finalizeAvatar(s3Key)` to set it on the agent.
1016
- */
1017
- presignAvatar(args: {
1018
- mimeType: string;
1019
- size: number;
1020
- }): Promise<AgentAvatarPresign>;
1021
- /**
1022
- * Finalize an avatar upload — validates ownership + size, then sets the
1023
- * agent's `avatarUrl` server-side. Returns the updated agent.
1219
+ * Resolve the primary cTrader Connection's credentials for the calling
1220
+ * agent. Unlike most providers, the cTrader Open API needs app-level auth
1221
+ * (`clientId` + `clientSecret`) AND account auth (`accessToken` +
1222
+ * `accountId`) on the socket, so `@alfe.ai/ctrader-mcp` self-fetches the
1223
+ * full set here at startup (the atlassian/google pattern). `clientId` /
1224
+ * `clientSecret` are the SST-sourced global app credentials the connect
1225
+ * endpoint injects — they are never persisted on the connection. `host` is
1226
+ * the resolved TLS endpoint (`live.ctraderapi.com` / `demo.ctraderapi.com`)
1227
+ * derived from the selected account's live/demo flag.
1024
1228
  */
1025
- finalizeAvatar(s3Key: string): Promise<AgentSelf>;
1026
- /** List the platform voice catalogue (ElevenLabs) so the agent can pick its own voice. */
1027
- listVoices(): Promise<{
1028
- voices: AgentVoice[];
1229
+ getCTraderCredentials(): Promise<{
1230
+ accessToken: string;
1231
+ refreshToken: string;
1232
+ accountId: string;
1233
+ host: string;
1234
+ clientId: string;
1235
+ clientSecret: string;
1029
1236
  }>;
1030
1237
  /**
1031
- * Mint a fresh AES-256 data key for a specific (secret, field) pair. The
1032
- * encryption context is rebuilt server-side from `auth.tenantId` + the body
1033
- * fields including `fieldKey`; the agent cannot forge context for a scope
1034
- * or field it doesn't own. Legacy single-envelope secrets are migrated to
1035
- * `field#value` rows by the data migration, so call with `fieldKey: "value"`
1036
- * to reach them.
1238
+ * Pattern A: multi-account credential fetch for cTrader.
1239
+ *
1240
+ * Unlike atlassian/salesforce (one Connection row per account/site), a
1241
+ * cTrader is MULTI-grant per agent: an agent may connect several distinct
1242
+ * cTrader logins, each its own Connection row keyed on `accountIdentifier =
1243
+ * ctid:<userId>` (Phase 1). This aggregates the *trading accounts* across
1244
+ * ALL of those Connection rows — each row contributes its `availableAccounts`
1245
+ * flattened, and every account carries ITS OWN grant's `accessToken` (the
1246
+ * token that authenticates that account against the cTrader Open API). One
1247
+ * OAuth grant still covers all accounts under that single login on one shared
1248
+ * token; only the `ctidTraderAccountId` and the protobuf socket `host` (live
1249
+ * vs demo) differ within a grant. Across grants the tokens differ, so the
1250
+ * token is now PER-ACCOUNT rather than hoisted to the top level.
1251
+ *
1252
+ * `host` per account is derived from the account's `isLive` flag
1253
+ * (`live.ctraderapi.com` / `demo.ctraderapi.com`) — the same mapping the
1254
+ * connect provider applies server-side when an account is auto-selected.
1255
+ *
1256
+ * `clientId` / `clientSecret` are the SST-sourced GLOBAL app credentials the
1257
+ * connect endpoint injects — identical across every Connection row (one
1258
+ * cTrader app), never persisted on a connection. We take them from the first
1259
+ * row that carries them.
1260
+ *
1261
+ * Accounts are deduped on `ctidTraderAccountId` first-wins: Spotware ids are
1262
+ * globally unique across logins, so a duplicate can only appear if the same
1263
+ * account somehow surfaced under two grants — first-wins keeps it
1264
+ * deterministic.
1265
+ *
1266
+ * `accounts` may be empty (no cTrader Connection at all), in which case we
1267
+ * return empty creds rather than throwing.
1037
1268
  */
1038
- generateSecretDataKey(args: {
1039
- scope: SecretScope;
1040
- scopeId: string;
1041
- secretId: string;
1042
- fieldKey: string;
1043
- }): Promise<GeneratedDataKey>;
1269
+ getCTraderAccounts(): Promise<{
1270
+ accounts: {
1271
+ ctidTraderAccountId: string;
1272
+ host: string;
1273
+ isLive: boolean;
1274
+ brokerName?: string;
1275
+ accountNumber?: string;
1276
+ accessToken: string;
1277
+ }[];
1278
+ clientId: string;
1279
+ clientSecret: string;
1280
+ }>;
1044
1281
  /**
1045
- * Unwrap a wrapped data key so the agent can decrypt the envelope locally.
1046
- * `fieldKey` MUST match the value supplied when the data key was generated
1047
- * (it's bound into KMS encryption context); mismatch fails with
1048
- * `InvalidCiphertextException`.
1282
+ * @deprecated Returns a single primary credential blob. Use
1283
+ * `getShopifyAccounts()` for the multi-account shape required by Pattern A
1284
+ * (`@alfe.ai/shopify-mcp` keys per-shop on the myshopify domain).
1049
1285
  */
1050
- decryptSecretDataKey(args: {
1051
- scope: SecretScope;
1052
- scopeId: string;
1053
- secretId: string;
1054
- fieldKey: string;
1055
- dataKeyCiphertext: string;
1056
- }): Promise<{
1057
- plaintextKey: string;
1286
+ getShopifyCredentials(): Promise<{
1287
+ accessToken: string;
1288
+ shopDomain: string;
1289
+ shopGid: string;
1290
+ shopName: string;
1291
+ apiVersion: string;
1058
1292
  }>;
1059
1293
  /**
1060
- * Create a new secret with one or more fields. Encrypted fields must arrive
1061
- * pre-sealed (the agent has already obtained per-field data keys via
1062
- * `generateSecretDataKey({ ..., fieldKey })` and AES-encrypted locally).
1063
- * Plaintext fields ship the value inline.
1294
+ * Pattern A: multi-account credential fetch for Shopify. Returns every
1295
+ * agent-scoped Shopify Connection. One OAuth grant maps to one store, so the
1296
+ * stable per-call selector is the store's myshopify domain (`shopDomain`),
1297
+ * NOT `accountIdentifier` — the connect provider keys `accountIdentifier` on
1298
+ * the immutable shop GID (falling back to the domain), so `shopDomain` is the
1299
+ * value the LLM passes and the plugin routes on.
1300
+ *
1301
+ * Each entry is shaped by the connect provider's `buildCredentialsResponse`:
1302
+ * `{ accessToken, shopDomain, shopGid, shopName, apiVersion }` — offline
1303
+ * Shopify tokens never expire, so there is NO token / expiry field and no
1304
+ * refresh method (unlike Salesforce). The GraphQL Admin API authenticates
1305
+ * purely on `X-Shopify-Access-Token`; no client credentials are on the wire.
1064
1306
  */
1065
- createSecret(args: {
1066
- scope: SecretScope;
1067
- scopeId: string;
1068
- secretId: string;
1069
- secretName: string;
1070
- category?: SecretCategory;
1071
- description?: string;
1072
- tags?: string[];
1073
- fields: {
1074
- key: string;
1075
- format?: FieldFormat;
1076
- sensitivity: FieldSensitivity;
1077
- value?: string;
1078
- envelope?: EncryptedEnvelopeV1;
1307
+ getShopifyAccounts(): Promise<{
1308
+ accounts: {
1309
+ connectionId: string;
1310
+ accountIdentifier: string;
1311
+ displayName: string | null;
1312
+ connectedAt: string;
1313
+ accessToken: string;
1314
+ shopDomain: string;
1315
+ shopGid: string;
1316
+ shopName: string;
1317
+ apiVersion: string;
1079
1318
  }[];
1080
- reason?: string;
1081
- }): Promise<SecretAggregate>;
1082
- /** Fetch the secret aggregate plus per-field encrypted envelopes. */
1083
- getSecret(args: {
1084
- scope: SecretScope;
1085
- scopeId: string;
1086
- secretId: string;
1087
- }): Promise<{
1088
- aggregate: SecretAggregate;
1089
- envelopes: FieldEnvelope[];
1090
- }>;
1091
- /** Fetch one field. Plaintext: value inline. Encrypted: envelope. */
1092
- getSecretField(args: {
1093
- scope: SecretScope;
1094
- scopeId: string;
1095
- secretId: string;
1096
- fieldKey: string;
1097
- }): Promise<{
1098
- key: string;
1099
- sensitivity: FieldSensitivity;
1100
- format?: FieldFormat;
1101
- value?: string;
1102
- envelope?: EncryptedEnvelopeV1;
1103
- rotatedAt?: string;
1104
- createdAt: string;
1105
- updatedAt: string;
1106
1319
  }>;
1107
- /** Add OR rotate one field. */
1108
- setSecretField(args: {
1109
- scope: SecretScope;
1110
- scopeId: string;
1111
- secretId: string;
1112
- fieldKey: string;
1113
- sensitivity: FieldSensitivity;
1114
- format?: FieldFormat;
1115
- value?: string;
1116
- envelope?: EncryptedEnvelopeV1;
1117
- reason?: string;
1118
- }): Promise<{
1119
- fieldKey: string;
1120
- rotated: boolean;
1320
+ /**
1321
+ * Pattern A: provider-parameterized multi-account credential fetch for the
1322
+ * social connectors (Bluesky, and the approval-gated backlog: X, Meta,
1323
+ * Threads, LinkedIn, Pinterest, TikTok, Reddit, YouTube).
1324
+ *
1325
+ * Unlike the bespoke `getGithubAccounts()` / `getXeroAccounts()` shapes,
1326
+ * this returns a UNIFORM normalized account shape so `@alfe.ai/social-mcp`'s
1327
+ * shared driver can require a single `account` selector on every
1328
+ * credential-touching tool regardless of platform. The backend
1329
+ * `api-agents/{provider}/accounts` route is already provider-generic; this
1330
+ * is the client-side normalization the plan (`do-we-need-any-moonlit-toucan`
1331
+ * Phase 0, step 5) calls for.
1332
+ *
1333
+ * `accountIdentifier` is the stable per-account selector the LLM should
1334
+ * pass back (for Bluesky: the account DID). `accessToken` carries whatever
1335
+ * the provider's `buildCredentialsResponse` bundles (for Bluesky: the JSON
1336
+ * session bundle — the driver parses the `accessJwt` out of it, or reads the
1337
+ * top-level `accessJwt` from `providerMetadata`-adjacent fields). Everything
1338
+ * else the driver needs for routing (handle, pdsHost, did, …) is on
1339
+ * `providerMetadata`.
1340
+ *
1341
+ * Token refresh is delegated to connect (never done in-plugin) via the
1342
+ * per-account route `POST /agent/connect/{provider}/accounts/{accountIdentifier}/refresh`
1343
+ * — call `refreshSocialAccount(provider, accountIdentifier)`. (The non-account
1344
+ * `POST /agent/connect/{provider}/refresh` route refreshes the provider's
1345
+ * PRIMARY connection, which is wrong under multi-account Pattern A.)
1346
+ */
1347
+ getSocialAccounts(provider: string): Promise<{
1348
+ provider: string;
1349
+ accounts: {
1350
+ connectionId: string;
1351
+ accountIdentifier: string;
1352
+ displayName: string | null;
1353
+ accessToken: string;
1354
+ providerMetadata: Record<string, unknown>;
1355
+ connectedAt: string;
1356
+ }[];
1121
1357
  }>;
1122
- /** Remove one field. */
1123
- removeSecretField(args: {
1124
- scope: SecretScope;
1125
- scopeId: string;
1126
- secretId: string;
1127
- fieldKey: string;
1128
- }): Promise<void>;
1129
- /** Update secret-level metadata (name/description/tags/category). */
1130
- updateSecretMetadata(args: {
1131
- scope: SecretScope;
1132
- scopeId: string;
1133
- secretId: string;
1134
- secretName?: string;
1135
- description?: string;
1136
- tags?: string[];
1137
- category?: SecretCategory;
1138
- reason?: string;
1139
- }): Promise<SecretAggregate>;
1140
- /** List metadata for secrets in a scope. Optional filters route through the byFacet GSI. */
1141
- listSecrets(args: {
1142
- scope: SecretScope;
1143
- scopeId: string;
1144
- category?: SecretCategory;
1145
- tag?: string;
1146
- fieldKey?: string;
1147
- }): Promise<SecretMetadata[]>;
1148
- /** Bounded changelog read — metadata-only audit entries. */
1149
- getSecretHistory(args: {
1150
- scope: SecretScope;
1151
- scopeId: string;
1152
- secretId: string;
1153
- limit?: number;
1154
- cursor?: string;
1155
- }): Promise<{
1156
- entries: ChangelogEntry[];
1157
- nextCursor?: string;
1358
+ /**
1359
+ * Pattern A: refresh a specific social Connection by its stable
1360
+ * `accountIdentifier` (for Bluesky: the account DID) via the
1361
+ * provider-generic per-account refresh route. The counterpart to
1362
+ * `getSocialAccounts(provider)`; `@alfe.ai/social-mcp` calls this on a
1363
+ * 401/ExpiredToken from the platform PDS/API, then re-fetches accounts to
1364
+ * pick up the rotated bundle.
1365
+ *
1366
+ * Refresh itself is ALWAYS delegated to connect — the plugin never calls
1367
+ * the platform's own refresh XRPC (e.g. `com.atproto.server.refreshSession`)
1368
+ * because connect owns the encrypted refresh token + rotation persistence
1369
+ * (Bluesky rotates the refreshJwt; a missed rotation kills the connection
1370
+ * after one refresh). The returned `accessToken` is whatever the provider's
1371
+ * `refreshToken` hook re-bundled (for Bluesky: the JSON session bundle with
1372
+ * the fresh `accessJwt`) — callers typically ignore it and re-fetch via
1373
+ * `getSocialAccounts` for a consistent shape.
1374
+ */
1375
+ refreshSocialAccount(provider: string, accountIdentifier: string): Promise<{
1376
+ accountIdentifier: string;
1377
+ accessToken: string;
1378
+ accessTokenExpiresAt: string;
1379
+ expiresAt: string;
1158
1380
  }>;
1159
- /** Delete a secret (and all its field rows + tag rows + changelog rows). */
1160
- deleteSecret(args: {
1161
- scope: SecretScope;
1162
- scopeId: string;
1163
- secretId: string;
1381
+ }
1382
+ //# sourceMappingURL=connect-credentials.d.ts.map
1383
+ //#endregion
1384
+ //#region src/domains/database.d.ts
1385
+ declare class DatabaseApi extends ApiBase {
1386
+ registerDatabaseCredentials(): Promise<{
1387
+ connectionString: string;
1388
+ username: string;
1389
+ password: string;
1390
+ databases: string[];
1391
+ }>;
1392
+ reportDatabaseAudit(entry: {
1393
+ database: string;
1394
+ collection: string;
1395
+ operation: string;
1396
+ summary?: string;
1164
1397
  }): Promise<void>;
1165
- /** Enumerate scopes (org/team/project/agent) this agent can access. */
1166
- listSecretScopes(): Promise<ScopeInfo[]>;
1398
+ }
1399
+ //# sourceMappingURL=database.d.ts.map
1400
+ //#endregion
1401
+ //#region src/domains/identity.d.ts
1402
+ declare class IdentityApi extends ApiBase {
1167
1403
  /**
1168
1404
  * Returns the calling agent's own identity context — `{ agentId, tenantId }`
1169
1405
  * decoded server-side from the agent API token. Used by the
@@ -1206,59 +1442,35 @@ declare class AgentApiClient {
1206
1442
  }>;
1207
1443
  mergeIdentities(survivorId: string, args: {
1208
1444
  mergedId: string;
1209
- changedBy: {
1210
- type: string;
1211
- id: string;
1212
- name?: string;
1213
- };
1214
1445
  }): Promise<{
1215
1446
  ok: boolean;
1216
1447
  error?: string;
1217
1448
  }>;
1218
- unmergeIdentity(identityId: string, args: {
1219
- changedBy: {
1220
- type: string;
1221
- id: string;
1222
- name?: string;
1223
- };
1224
- }): Promise<{
1449
+ unmergeIdentity(identityId: string): Promise<{
1225
1450
  ok: boolean;
1226
1451
  error?: string;
1227
1452
  }>;
1228
1453
  addIdentityNote(identityId: string, args: {
1229
1454
  content: string;
1230
1455
  category?: string;
1231
- changedBy: {
1232
- type: string;
1233
- id: string;
1234
- name?: string;
1235
- };
1236
1456
  }): Promise<{
1237
1457
  noteId: string | null;
1238
1458
  }>;
1239
1459
  tagIdentity(identityId: string, args: {
1240
1460
  tag: string;
1241
1461
  action: "add" | "remove";
1242
- changedBy: {
1243
- type: string;
1244
- id: string;
1245
- name?: string;
1246
- };
1247
1462
  }): Promise<{
1248
1463
  ok: boolean;
1249
1464
  }>;
1250
1465
  getIdentityChangelog(identityId: string, args?: {
1251
1466
  limit?: number;
1467
+ cursor?: string;
1252
1468
  }): Promise<{
1253
1469
  entries: unknown[];
1470
+ cursor: string | null;
1254
1471
  }>;
1255
1472
  rollbackIdentity(identityId: string, args: {
1256
1473
  targetVersion: number;
1257
- changedBy: {
1258
- type: string;
1259
- id: string;
1260
- name?: string;
1261
- };
1262
1474
  }): Promise<{
1263
1475
  ok: boolean;
1264
1476
  entry?: unknown;
@@ -1297,7 +1509,7 @@ declare class AgentApiClient {
1297
1509
  verified: boolean;
1298
1510
  identityId?: string;
1299
1511
  /** Phase 2: how the confirm resolved — Scenario A vs B. */
1300
- action?: "merged" | "contact_verified";
1512
+ action?: "merged" | "contact_verified" | "already_confirmed";
1301
1513
  error?: string;
1302
1514
  }>;
1303
1515
  /**
@@ -1326,6 +1538,62 @@ declare class AgentApiClient {
1326
1538
  identityId: string | null;
1327
1539
  status: string;
1328
1540
  }>;
1541
+ }
1542
+ //# sourceMappingURL=identity.d.ts.map
1543
+ //#endregion
1544
+ //#region src/domains/images.d.ts
1545
+ declare class ImagesApi extends ApiBase {
1546
+ /**
1547
+ * Generate an image from a text prompt and get back a STABLE, public URL
1548
+ * (served from the agent-assets CDN — it does not expire). Embed the returned
1549
+ * `imageUrl` in a reply as markdown to show it to the user.
1550
+ *
1551
+ * ASYNC: `gpt-image-1` routinely runs 30–60s, which exceeds the API Gateway
1552
+ * 30s ceiling, so this enqueues a job (`POST /agent/images/generate` →
1553
+ * `jobId`) then polls (`GET /agent/images/{jobId}`) until it completes. The
1554
+ * worker's real failure message (e.g. an unsupported `size`) surfaces via the
1555
+ * job's `error` field.
1556
+ */
1557
+ generateImage(args: {
1558
+ prompt: string;
1559
+ model?: string;
1560
+ size?: string;
1561
+ quality?: string;
1562
+ }): Promise<{
1563
+ imageUrl: string;
1564
+ model: string;
1565
+ }>;
1566
+ }
1567
+ //# sourceMappingURL=images.d.ts.map
1568
+ //#endregion
1569
+ //#region src/domains/integrations.d.ts
1570
+ declare class IntegrationsApi extends ApiBase {
1571
+ listIntegrations(): Promise<IntegrationInstall[]>;
1572
+ getIntegrationConfig(integrationId: string): Promise<IntegrationConfigResult>;
1573
+ updateIntegrationConfig(integrationId: string, config: Record<string, unknown>): Promise<void>;
1574
+ installIntegration(integrationId: string, options?: {
1575
+ version?: string;
1576
+ config?: Record<string, unknown>;
1577
+ }): Promise<IntegrationInstall>;
1578
+ removeIntegration(integrationId: string): Promise<IntegrationInstall>;
1579
+ getOAuthUrl(provider: string, scopes?: string[]): Promise<{
1580
+ url: string;
1581
+ provider: string;
1582
+ expiresIn: number;
1583
+ }>;
1584
+ getOAuthStatus(provider: string): Promise<{
1585
+ provider: string;
1586
+ connected: boolean;
1587
+ config?: Record<string, string>;
1588
+ }>;
1589
+ getRegistry(): Promise<{
1590
+ integrations: RegistryEntry[];
1591
+ }>;
1592
+ }
1593
+ //# sourceMappingURL=integrations.d.ts.map
1594
+ //#endregion
1595
+ //#region src/domains/memory.d.ts
1596
+ declare class MemoryApi extends ApiBase {
1329
1597
  memorySearch(query: string, opts?: {
1330
1598
  limit?: number;
1331
1599
  topic?: string;
@@ -1373,8 +1641,21 @@ declare class AgentApiClient {
1373
1641
  messageCount: number;
1374
1642
  }>;
1375
1643
  memoryLoadContext(tier?: number, topicHint?: string): Promise<{
1644
+ tier: number;
1645
+ facts: {
1646
+ subject: string;
1647
+ predicate: string;
1648
+ object: string;
1649
+ since: string;
1650
+ }[];
1651
+ memories: {
1652
+ text: string;
1653
+ topic: string;
1654
+ subtopic: string;
1655
+ score: number;
1656
+ }[];
1657
+ tokenEstimate: number;
1376
1658
  formatted: string;
1377
- [key: string]: unknown;
1378
1659
  }>;
1379
1660
  memoryLookupEntity(subject: string): Promise<{
1380
1661
  subject: string;
@@ -1400,198 +1681,218 @@ declare class AgentApiClient {
1400
1681
  }>;
1401
1682
  memoryStats(): Promise<{
1402
1683
  vectorCount: number;
1403
- tripleCount: number;
1404
- storageEstimateBytes: number;
1405
- lastIngestionAt?: string;
1406
- }>;
1407
- memoryLearn(args: {
1408
- text: string;
1409
- source?: string;
1410
- sourceType?: "file" | "url" | "inline";
1411
- metadata?: {
1412
- sessionId?: string;
1413
- channelId?: string;
1414
- userName?: string;
1415
- };
1416
- }): Promise<{
1417
- memoriesStored: number;
1418
- triplesStored: number;
1419
- chunks: number;
1420
- source?: string;
1421
- }>;
1422
- memoryBootstrapStatus(): Promise<{
1423
- synced: boolean;
1424
- syncedAt?: string;
1425
- sessionsBackfillSynced?: boolean;
1426
- sessionsBackfillSyncedAt?: string;
1427
- }>;
1428
- memoryBootstrapStatusMark(scope?: "files" | "sessions"): Promise<{
1429
- synced: true;
1430
- syncedAt: string;
1431
- }>;
1432
- sendSms(args: {
1433
- to: string;
1434
- body: string;
1435
- }): Promise<{
1436
- sent: boolean;
1437
- sid: string;
1438
- }>;
1439
- searchWeb(params: {
1440
- query: string;
1441
- count?: number;
1442
- offset?: number;
1443
- country?: string;
1444
- freshness?: string;
1445
- }): Promise<unknown>;
1446
- searchImages(params: {
1447
- query: string;
1448
- count?: number;
1449
- }): Promise<unknown>;
1450
- searchNews(params: {
1451
- query: string;
1452
- count?: number;
1453
- freshness?: string;
1454
- }): Promise<unknown>;
1455
- /** Search news across the selected provider's corpus. → POST /agent/news/search */
1456
- newsSearch(params: {
1457
- query: string;
1458
- provider?: NewsProvider;
1459
- source?: string;
1460
- from?: string;
1461
- to?: string;
1462
- language?: string;
1463
- category?: string;
1464
- limit?: number;
1465
- }): Promise<NewsResult>;
1466
- /** Top headlines for the selected provider. → POST /agent/news/headlines */
1467
- newsHeadlines(params?: {
1468
- provider?: NewsProvider;
1469
- category?: string;
1470
- source?: string;
1471
- language?: string;
1472
- limit?: number;
1473
- }): Promise<NewsResult>;
1474
- /**
1475
- * Semantic search across the agent's member scopes. Fan-out is gated
1476
- * server-side by `listScopes` set-inclusion (fail-closed). Pass
1477
- * `scopeType` + `scopeId` to narrow to one scope; a non-member scope
1478
- * yields empty results (never a cross-scope leak).
1479
- */
1480
- knowledgeSearch(query: string, opts?: {
1481
- limit?: number;
1482
- scopeType?: KnowledgeScopeType;
1483
- scopeId?: string;
1484
- }): Promise<KnowledgeSearchResult>;
1485
- /** Enumerate the scopes (org + teams + projects) this agent belongs to. */
1486
- listScopes(): Promise<{
1487
- scopes: KnowledgeScope[];
1488
- }>;
1489
- /** Read a scope's structured knowledge profile (after membership check). */
1490
- getScopeProfile(scopeType: KnowledgeScopeType, scopeId: string): Promise<KnowledgeProfile>;
1491
- /** List a scope's docs (the org-files corpus; mirrored to shared/<scope>/). */
1492
- listScopeDocs(scopeType: KnowledgeScopeType, scopeId: string, opts?: {
1493
- limit?: number;
1494
- cursor?: string;
1684
+ tripleCount: number;
1685
+ storageEstimateBytes: number;
1686
+ lastIngestionAt?: string;
1687
+ }>;
1688
+ memoryLearn(args: {
1689
+ text: string;
1690
+ source?: string;
1691
+ sourceType?: "file" | "url" | "inline";
1692
+ metadata?: {
1693
+ sessionId?: string;
1694
+ channelId?: string;
1695
+ userName?: string;
1696
+ };
1495
1697
  }): Promise<{
1496
- files: KnowledgeDoc[];
1497
- nextCursor: string | null;
1698
+ memoriesStored: number;
1699
+ triplesStored: number;
1700
+ chunks: number;
1701
+ source?: string;
1702
+ }>;
1703
+ memoryBootstrapStatus(): Promise<{
1704
+ synced: boolean;
1705
+ syncedAt?: string;
1706
+ sessionsBackfillSynced?: boolean;
1707
+ sessionsBackfillSyncedAt?: string;
1708
+ }>;
1709
+ memoryBootstrapStatusMark(scope?: "files" | "sessions"): Promise<{
1710
+ synced: true;
1711
+ syncedAt: string;
1498
1712
  }>;
1713
+ }
1714
+ //# sourceMappingURL=memory.d.ts.map
1715
+ //#endregion
1716
+ //#region src/domains/secrets.d.ts
1717
+ declare class SecretsApi extends ApiBase {
1499
1718
  /**
1500
- * Read the full text of a scope doc. Resolves a presigned download URL
1501
- * from `services/org`, then fetches the bytes directly from S3 (the one
1502
- * legitimate raw fetch in a plugin — same pattern as sync).
1719
+ * Mint a fresh AES-256 data key for a specific (secret, field) pair. The
1720
+ * encryption context is rebuilt server-side from `auth.tenantId` + the body
1721
+ * fields including `fieldKey`; the agent cannot forge context for a scope
1722
+ * or field it doesn't own. Legacy single-envelope secrets are migrated to
1723
+ * `field#value` rows by the data migration, so call with `fieldKey: "value"`
1724
+ * to reach them.
1503
1725
  */
1504
- readScopeDoc(scopeType: KnowledgeScopeType, scopeId: string, filePath: string): Promise<{
1505
- filePath: string;
1506
- text: string;
1507
- }>;
1726
+ generateSecretDataKey(args: {
1727
+ scope: SecretScope;
1728
+ scopeId: string;
1729
+ secretId: string;
1730
+ fieldKey: string;
1731
+ }): Promise<GeneratedDataKey>;
1508
1732
  /**
1509
- * Write (create or overwrite) a scope doc. Two-step presigned upload:
1510
- * `services/org` returns a signed URL plus `requiredHeaders` (author /
1511
- * authorKind / message as `x-amz-meta-*`) that MUST be sent verbatim on
1512
- * the PUT, alongside the same `Content-Type` that was signed. Author and
1513
- * authorKind are server-set from the agent token — never trusted here.
1733
+ * Unwrap a wrapped data key so the agent can decrypt the envelope locally.
1734
+ * `fieldKey` MUST match the value supplied when the data key was generated
1735
+ * (it's bound into KMS encryption context); mismatch fails with
1736
+ * `InvalidCiphertextException`.
1514
1737
  */
1515
- writeScopeDoc(scopeType: KnowledgeScopeType, scopeId: string, filePath: string, content: string, opts?: {
1516
- contentType?: string;
1517
- message?: string;
1738
+ decryptSecretDataKey(args: {
1739
+ scope: SecretScope;
1740
+ scopeId: string;
1741
+ secretId: string;
1742
+ fieldKey: string;
1743
+ dataKeyCiphertext: string;
1518
1744
  }): Promise<{
1519
- filePath: string;
1745
+ plaintextKey: string;
1520
1746
  }>;
1521
1747
  /**
1522
- * Open a change request against a scope's knowledge resource. For a doc
1523
- * create/update, `services/org` returns a presigned staging PUT; this method
1524
- * uploads the proposed `content` to it (echoing the same Content-Type that
1525
- * was signed), mirroring `writeScopeDoc`. The staged body is applied to the
1526
- * canonical doc — attributed to this agent — only when a reviewer approves.
1527
- */
1528
- proposeScopeChange(scopeType: KnowledgeScopeType, scopeId: string, input: ProposeScopeChangeInput): Promise<KnowledgeChangeRequest>;
1529
- /**
1530
- * List the agent's OWN change requests in a scope (filtered server-side to
1531
- * this agent as proposer). Pass `status` to narrow to open / approved / etc.
1748
+ * Create a new secret with one or more fields. Encrypted fields must arrive
1749
+ * pre-sealed (the agent has already obtained per-field data keys via
1750
+ * `generateSecretDataKey({ ..., fieldKey })` and AES-encrypted locally).
1751
+ * Plaintext fields ship the value inline.
1532
1752
  */
1533
- listScopeChangeRequests(scopeType: KnowledgeScopeType, scopeId: string, opts?: {
1534
- status?: ChangeRequestStatus;
1535
- limit?: number;
1536
- cursor?: string;
1753
+ createSecret(args: {
1754
+ scope: SecretScope;
1755
+ scopeId: string;
1756
+ secretId: string;
1757
+ secretName: string;
1758
+ category?: SecretCategory;
1759
+ description?: string;
1760
+ tags?: string[];
1761
+ fields: {
1762
+ key: string;
1763
+ format?: FieldFormat;
1764
+ sensitivity: FieldSensitivity;
1765
+ value?: string;
1766
+ envelope?: EncryptedEnvelopeV1;
1767
+ }[];
1768
+ reason?: string;
1769
+ }): Promise<SecretAggregate>;
1770
+ /** Fetch the secret aggregate plus per-field encrypted envelopes. */
1771
+ getSecret(args: {
1772
+ scope: SecretScope;
1773
+ scopeId: string;
1774
+ secretId: string;
1537
1775
  }): Promise<{
1538
- changeRequests: KnowledgeChangeRequest[];
1539
- nextCursor: string | null;
1776
+ aggregate: SecretAggregate;
1777
+ envelopes: FieldEnvelope[];
1540
1778
  }>;
1541
- registerDatabaseCredentials(): Promise<{
1542
- connectionString: string;
1543
- username: string;
1544
- password: string;
1545
- databases: string[];
1779
+ /** Fetch one field. Plaintext: value inline. Encrypted: envelope. */
1780
+ getSecretField(args: {
1781
+ scope: SecretScope;
1782
+ scopeId: string;
1783
+ secretId: string;
1784
+ fieldKey: string;
1785
+ }): Promise<{
1786
+ key: string;
1787
+ sensitivity: FieldSensitivity;
1788
+ format?: FieldFormat;
1789
+ value?: string;
1790
+ envelope?: EncryptedEnvelopeV1;
1791
+ rotatedAt?: string;
1792
+ createdAt: string;
1793
+ updatedAt: string;
1546
1794
  }>;
1547
- reportDatabaseAudit(entry: {
1548
- database: string;
1549
- collection: string;
1550
- operation: string;
1551
- summary?: string;
1795
+ /** Add OR rotate one field. */
1796
+ setSecretField(args: {
1797
+ scope: SecretScope;
1798
+ scopeId: string;
1799
+ secretId: string;
1800
+ fieldKey: string;
1801
+ sensitivity: FieldSensitivity;
1802
+ format?: FieldFormat;
1803
+ value?: string;
1804
+ envelope?: EncryptedEnvelopeV1;
1805
+ reason?: string;
1806
+ }): Promise<{
1807
+ fieldKey: string;
1808
+ rotated: boolean;
1809
+ }>;
1810
+ /** Remove one field. */
1811
+ removeSecretField(args: {
1812
+ scope: SecretScope;
1813
+ scopeId: string;
1814
+ secretId: string;
1815
+ fieldKey: string;
1552
1816
  }): Promise<void>;
1553
- requestBrowserTakeover(args: {
1554
- instructions: string;
1555
- url?: string;
1556
- conversationId?: string;
1817
+ /** Update secret-level metadata (name/description/tags/category). */
1818
+ updateSecretMetadata(args: {
1819
+ scope: SecretScope;
1820
+ scopeId: string;
1821
+ secretId: string;
1822
+ secretName?: string;
1823
+ description?: string;
1824
+ tags?: string[];
1825
+ category?: SecretCategory;
1826
+ reason?: string;
1827
+ }): Promise<SecretAggregate>;
1828
+ /** List metadata for secrets in a scope. Optional filters route through the byFacet GSI. */
1829
+ listSecrets(args: {
1830
+ scope: SecretScope;
1831
+ scopeId: string;
1832
+ category?: SecretCategory;
1833
+ tag?: string;
1834
+ fieldKey?: string;
1835
+ }): Promise<SecretMetadata[]>;
1836
+ /** Bounded changelog read — metadata-only audit entries. */
1837
+ getSecretHistory(args: {
1838
+ scope: SecretScope;
1839
+ scopeId: string;
1840
+ secretId: string;
1841
+ limit?: number;
1842
+ cursor?: string;
1557
1843
  }): Promise<{
1558
- sessionId: string;
1559
- status: string;
1844
+ entries: ChangelogEntry[];
1845
+ nextCursor?: string;
1560
1846
  }>;
1561
- getRemoteSession(sessionId: string): Promise<RemoteSessionInfo>;
1562
- completeRemoteSession(sessionId: string): Promise<{
1847
+ /** Delete a secret (and all its field rows + tag rows + changelog rows). */
1848
+ deleteSecret(args: {
1849
+ scope: SecretScope;
1850
+ scopeId: string;
1851
+ secretId: string;
1852
+ }): Promise<void>;
1853
+ /** Enumerate scopes (org/team/project/agent) this agent can access. */
1854
+ listSecretScopes(): Promise<ScopeInfo[]>;
1855
+ }
1856
+ //# sourceMappingURL=secrets.d.ts.map
1857
+ //#endregion
1858
+ //#region src/domains/teams.d.ts
1859
+ declare class TeamsApi extends ApiBase {
1860
+ getTeamsCredentials(): Promise<{
1861
+ agentId: string;
1862
+ tenantId: string;
1863
+ azureAppId: string;
1864
+ azureBotId: string;
1865
+ azureClientSecret: string;
1866
+ botDisplayName?: string;
1867
+ teamsTenantId?: string;
1868
+ serviceUrl?: string;
1869
+ }>;
1870
+ sendTeamsMessage(data: {
1871
+ conversationId: string;
1872
+ text?: string;
1873
+ adaptiveCard?: Record<string, unknown>;
1874
+ }): Promise<{
1563
1875
  ok: boolean;
1876
+ activityId: string;
1564
1877
  }>;
1565
- /**
1566
- * Issue a request that returns the raw `Response` (no JSON parsing, no
1567
- * forced Content-Type). The caller sets `Content-Type`/`Accept` on `headers`
1568
- * and reads the body itself (`arrayBuffer()` / `json()`).
1569
- *
1570
- * A single retry fires only on the same transient statuses `request()`
1571
- * retries (authorizer-timeout 500 + LB 502/503/504) and transient network
1572
- * errors — before the route handler runs — so re-issuing a POST does not
1573
- * risk a duplicate side effect. Voice TTS/STT are effectively idempotent
1574
- * (re-synthesize / re-transcribe) and meter server-side keyed on the
1575
- * gateway requestId, so a retried transcription doesn't double-bill.
1576
- */
1577
- private rawFetch;
1578
- /**
1579
- * Text-to-speech. Returns raw PCM audio bytes plus their framing — the
1580
- * voice service defaults to 24 kHz / mono / 16-bit. Wrap in a WAV container
1581
- * to produce a playable file. Metered per character against the tenant
1582
- * credit pool server-side; TTS completes regardless of metering outcome.
1583
- */
1584
- tts(args: VoiceTtsArgs): Promise<VoiceTtsResult>;
1585
- /**
1586
- * Speech-to-text. Accepts raw linear16 (16-bit LE) mono PCM — NOT a WAV or
1587
- * other container (the endpoint transcribes with a fixed linear16 encoding,
1588
- * so a container header would be transcribed as noise). Strip any WAV header
1589
- * and pass `sampleRate` from it before calling. Metered by transcribed
1590
- * duration against the tenant credit pool server-side.
1591
- */
1592
- stt(args: VoiceSttArgs): Promise<VoiceSttResult>;
1878
+ listTeamsChannels(): Promise<{
1879
+ channels: {
1880
+ id: string;
1881
+ name: string;
1882
+ description?: string;
1883
+ }[];
1884
+ }>;
1885
+ }
1886
+ //# sourceMappingURL=teams.d.ts.map
1887
+
1888
+ //#endregion
1889
+ //#region src/index.d.ts
1890
+ interface AgentApiClient extends SyncApi, IntegrationsApi, WorkspaceApi, ConnectCredentialsApi, TeamsApi, ChatApi, SecretsApi, IdentityApi, MemoryApi, SearchApi, KnowledgeApi, DatabaseApi, MobileApi, RemoteApi, SelfApi, VoiceApi, ImagesApi, WebhooksApi {}
1891
+ declare class AgentApiClient extends ApiBase {
1892
+ constructor(config: AgentApiClientConfig);
1593
1893
  }
1594
1894
  //# sourceMappingURL=index.d.ts.map
1895
+
1595
1896
  //#endregion
1596
1897
  //#endregion
1597
1898
  //#region ../chat/dist/index.d.ts
@@ -1606,7 +1907,7 @@ interface ChatServiceClientOptions {
1606
1907
  /** Agent API key for Bearer auth */
1607
1908
  apiKey: string;
1608
1909
  /** Called when the chat service sends an RPC request */
1609
- onRequest: (request: RpcRequest) => void;
1910
+ onRequest: (request: RpcRequest) => void | Promise<void>;
1610
1911
  /** Called when connection state changes */
1611
1912
  onConnectionChange?: (connected: boolean) => void;
1612
1913
  /** Optional logger (defaults to console) */
@@ -1628,12 +1929,12 @@ interface Logger {
1628
1929
  }
1629
1930
  //#endregion
1630
1931
  //#region src/client.d.ts
1631
-
1632
1932
  declare class ChatServiceClient {
1633
1933
  private readonly options;
1634
1934
  private ws;
1635
1935
  private stopped;
1636
1936
  private connected;
1937
+ private connectionGeneration;
1637
1938
  private retryCount;
1638
1939
  private retryTimer;
1639
1940
  private heartbeatTimer;
@@ -1642,7 +1943,7 @@ declare class ChatServiceClient {
1642
1943
  private pendingRequests;
1643
1944
  private requestCounter;
1644
1945
  private messageQueue;
1645
- private readonly MAX_QUEUE_SIZE;
1946
+ private queuedBytes;
1646
1947
  constructor(options: ChatServiceClientOptions);
1647
1948
  get isConnected(): boolean;
1648
1949
  /** Start connecting to the chat service. */
@@ -1663,8 +1964,13 @@ declare class ChatServiceClient {
1663
1964
  */
1664
1965
  sendRequest(method: string, params: Record<string, unknown>, timeoutMs?: number): Promise<Record<string, unknown>>;
1665
1966
  private flushMessageQueue;
1967
+ private enqueueMessage;
1666
1968
  private flushPendingRequests;
1969
+ private rejectPendingRequest;
1667
1970
  private doConnect;
1971
+ private isCurrentSocket;
1972
+ private setConnected;
1973
+ private notifyConnectionChange;
1668
1974
  private handleMessage;
1669
1975
  private scheduleReconnect;
1670
1976
  /**
@@ -1836,14 +2142,20 @@ declare const WARM_STREAMING_SUPPORTED = false;
1836
2142
  * posture). An inbound chat message could try to induce a destructive shell
1837
2143
  * command, and these turns run unattended on the user's machine. We therefore
1838
2144
  * pass an explicit allow-list of read/analysis/edit tools and DENY Bash by
1839
- * default, and use `--permission-mode default` (NEVER `bypassPermissions` /
2145
+ * default, and use `--permission-mode dontAsk` (NEVER `bypassPermissions` /
1840
2146
  * `--dangerously-skip-permissions`). See DEVELOPING.md → "Tool-permission
1841
2147
  * posture". Bash is intentionally absent — a bridged turn cannot run arbitrary
1842
2148
  * shell. Callers that want a wider set pass `allowedTools` explicitly.
1843
2149
  */
1844
2150
  declare const DEFAULT_ALLOWED_TOOLS: readonly ["Read", "Grep", "Glob", "LS", "Edit", "Write", "WebFetch", "WebSearch", "Task", "TodoWrite"];
1845
- /** Sane default permission posture. NEVER `bypassPermissions`. */
1846
- declare const DEFAULT_PERMISSION_MODE = "default";
2151
+ declare const CLAUDE_PERMISSION_MODES: readonly ["acceptEdits", "auto", "manual", "dontAsk", "plan"];
2152
+ type ClaudePermissionMode = (typeof CLAUDE_PERMISSION_MODES)[number];
2153
+ /**
2154
+ * Headless-safe permission posture supported by current Claude CLI releases.
2155
+ * Allow-listed tools run; any permission prompt the bridge cannot answer is
2156
+ * denied. `bypassPermissions` is deliberately not representable.
2157
+ */
2158
+ declare const DEFAULT_PERMISSION_MODE: ClaudePermissionMode;
1847
2159
  /** How a turn ended, surfaced to the host so it can settle / persist. */
1848
2160
  interface DriverTurnResult {
1849
2161
  /** The claude session id observed on the `system:init` event (for --resume). */
@@ -1875,7 +2187,7 @@ interface RunTurnParams {
1875
2187
  /** Tool allow-list (defaults to DEFAULT_ALLOWED_TOOLS). */
1876
2188
  allowedTools?: readonly string[];
1877
2189
  /** Permission mode (defaults to DEFAULT_PERMISSION_MODE — never bypass). */
1878
- permissionMode?: string;
2190
+ permissionMode?: ClaudePermissionMode;
1879
2191
  /** Per-emission callback so the host can stream deltas/activity live. */
1880
2192
  onEmission: (emission: MapperEmission) => void;
1881
2193
  /** Wall-clock override for the mapper (tests). Defaults to Date.now. */
@@ -1890,6 +2202,8 @@ interface RunTurnParams {
1890
2202
  * cap, but the late settle is harmlessly no-op'd by the chat service.
1891
2203
  */
1892
2204
  declare const TURN_TIMEOUT_MS = 300000;
2205
+ /** Grace after SIGINT before SIGKILL + local settlement. Keeps E2 under 305s. */
2206
+ declare const TERMINATION_GRACE_MS = 2000;
1893
2207
  /**
1894
2208
  * Spawns and drives `claude` subprocesses. Tracks a SINGLE in-flight child, so
1895
2209
  * the host creates ONE driver PER TURN (`ClaudeCodeHost.makeDriver`) — a driver
@@ -1898,6 +2212,7 @@ declare const TURN_TIMEOUT_MS = 300000;
1898
2212
  */
1899
2213
  declare class SessionDriver {
1900
2214
  private child;
2215
+ private abortCurrent;
1901
2216
  private readonly bin;
1902
2217
  private readonly baseEnv;
1903
2218
  private readonly log;
@@ -1971,6 +2286,9 @@ declare class ClaudeCodeHost {
1971
2286
  private readonly seenIdempotencyKeys;
1972
2287
  /** RPC sessionKey → resolved SessionDriver so chat.abort can SIGINT the child. */
1973
2288
  private activeDriverBySession;
2289
+ private claudeSessionSave;
2290
+ private stopping;
2291
+ private stopPromise;
1974
2292
  constructor(cfg: ClaudeCodeHostConfig, deps?: {
1975
2293
  /** Per-turn driver factory (test seam). Called once per turn. */
1976
2294
  makeDriver?: () => SessionDriver;
@@ -1979,8 +2297,8 @@ declare class ClaudeCodeHost {
1979
2297
  });
1980
2298
  /** Start the chat WS. Non-blocking — the client reconnects internally. */
1981
2299
  start(): Promise<void>;
1982
- /** Stop the chat WS (SIGTERM path). */
1983
- stop(): void;
2300
+ /** Stop admission, abort owned children, and give active turns time to settle. */
2301
+ stop(): Promise<void>;
1984
2302
  /**
1985
2303
  * Inbound RPC dispatch. Invoked by the chat client's `onRequest` in
1986
2304
  * production; also the test seam (drive `agent`/`chat.abort`/… directly).
@@ -2002,6 +2320,7 @@ declare class ClaudeCodeHost {
2002
2320
  private ensureSession;
2003
2321
  private loadClaudeSessionIds;
2004
2322
  private saveClaudeSessionIds;
2323
+ private rememberClaudeSessionId;
2005
2324
  private pruneIdempotency;
2006
2325
  }
2007
2326
  /** Strip the `agent:{agentId}:` prefix from a full server session key. */
@@ -2160,4 +2479,4 @@ declare function listSessions(filters?: {
2160
2479
  */
2161
2480
  declare function resolveHostConfig(): ClaudeCodeHostConfig;
2162
2481
  //#endregion
2163
- export { type ActivityEmission, BRIDGE_ENV_VAR, type ChatActivityRecord, type ChatMessage, ClaudeCodeHost, type ClaudeCodeHostConfig, DEFAULT_ALLOWED_TOOLS, DEFAULT_PERMISSION_MODE, type DriverTurnResult, type EndEmission, type MapperEmission, type MapperState, type RunTurnParams, SCRUBBED_ANTHROPIC_ENV_VARS, type SessionData, SessionDriver, type SessionSummary, TURN_TIMEOUT_MS, type TextEmission, type ThinkingActivity, type ToolActivity, WARM_STREAMING_SUPPORTED, addMessage, appendActivity, buildChildEnv, collectTurnActivityRecords, createMapperState, createSession, getSession, listSessions, mapStreamEvent, mapStreamEvents, resolveHostConfig, saveSession, stripAgentPrefix };
2482
+ export { type ActivityEmission, BRIDGE_ENV_VAR, CLAUDE_PERMISSION_MODES, type ChatActivityRecord, type ChatMessage, ClaudeCodeHost, type ClaudeCodeHostConfig, type ClaudePermissionMode, DEFAULT_ALLOWED_TOOLS, DEFAULT_PERMISSION_MODE, type DriverTurnResult, type EndEmission, type MapperEmission, type MapperState, type RunTurnParams, SCRUBBED_ANTHROPIC_ENV_VARS, type SessionData, SessionDriver, type SessionSummary, TERMINATION_GRACE_MS, TURN_TIMEOUT_MS, type TextEmission, type ThinkingActivity, type ToolActivity, WARM_STREAMING_SUPPORTED, addMessage, appendActivity, buildChildEnv, collectTurnActivityRecords, createMapperState, createSession, getSession, listSessions, mapStreamEvent, mapStreamEvents, resolveHostConfig, saveSession, stripAgentPrefix };