aamp-acp-bridge 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @byted-meego/aamp-acp-bridge
2
+
3
+ Config-driven bridge that connects ACP-compatible agents to the AAMP email network.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @byted-meego/aamp-acp-bridge
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ Initialize a config file:
14
+
15
+ ```bash
16
+ npx --registry=https://bnpm.byted.org @byted-meego/aamp-acp-bridge init
17
+ ```
18
+
19
+ Start the bridge:
20
+
21
+ ```bash
22
+ npx --registry=https://bnpm.byted.org @byted-meego/aamp-acp-bridge start --config bridge.json
23
+ ```
24
+
25
+ By default, agent credentials are stored under `~/.acp-bridge/`.
26
+
27
+ ## Config
28
+
29
+ Minimal example:
30
+
31
+ ```json
32
+ {
33
+ "aampHost": "https://meshmail.ai",
34
+ "rejectUnauthorized": false,
35
+ "agents": [
36
+ {
37
+ "name": "claude",
38
+ "acpCommand": "claude",
39
+ "slug": "claude-bridge",
40
+ "credentialsFile": "~/.acp-bridge/.aamp-claude.json",
41
+ "senderWhitelist": [
42
+ "system@aamp.local"
43
+ ]
44
+ }
45
+ ]
46
+ }
47
+ ```
48
+
49
+ `senderWhitelist` is optional. If configured, the bridge only accepts tasks from those email addresses.
50
+ `credentialsFile` is optional. If omitted, the bridge uses `~/.acp-bridge/.aamp-<agent>.json`.
@@ -0,0 +1,42 @@
1
+ export interface AcpEvent {
2
+ eventVersion?: number;
3
+ sessionId?: string;
4
+ requestId?: string;
5
+ seq?: number;
6
+ type?: string;
7
+ content?: string;
8
+ [key: string]: unknown;
9
+ }
10
+ export interface AcpResult {
11
+ output: string;
12
+ events: AcpEvent[];
13
+ }
14
+ /**
15
+ * Wrapper around acpx CLI.
16
+ * Invokes acpx as a subprocess and parses NDJSON output.
17
+ */
18
+ export declare class AcpxClient {
19
+ private cwd;
20
+ constructor(cwd?: string);
21
+ /**
22
+ * Ensure a named ACP session exists for the given agent.
23
+ */
24
+ ensureSession(agent: string, sessionName: string): Promise<string>;
25
+ /**
26
+ * Send a prompt to an ACP agent and wait for completion.
27
+ * Collects all stdout + stderr output and extracts the agent's response.
28
+ */
29
+ prompt(agent: string, sessionName: string, text: string): Promise<AcpResult>;
30
+ /**
31
+ * Cancel the current operation in a session.
32
+ */
33
+ cancel(agent: string, sessionName: string): Promise<void>;
34
+ /**
35
+ * Close a session.
36
+ */
37
+ close(agent: string, sessionName: string): Promise<void>;
38
+ /**
39
+ * Execute an acpx command and return stdout.
40
+ */
41
+ private exec;
42
+ }
@@ -0,0 +1,97 @@
1
+ import { spawn } from 'node:child_process';
2
+ /**
3
+ * Wrapper around acpx CLI.
4
+ * Invokes acpx as a subprocess and parses NDJSON output.
5
+ */
6
+ export class AcpxClient {
7
+ cwd;
8
+ constructor(cwd) {
9
+ this.cwd = cwd ?? process.cwd();
10
+ }
11
+ /**
12
+ * Ensure a named ACP session exists for the given agent.
13
+ */
14
+ async ensureSession(agent, sessionName) {
15
+ const result = await this.exec(agent, ['sessions', 'ensure', '--name', sessionName]);
16
+ // Try to extract sessionId from the JSON output
17
+ try {
18
+ const data = JSON.parse(result.trim().split('\n').pop() ?? '{}');
19
+ return data.sessionId ?? sessionName;
20
+ }
21
+ catch {
22
+ return sessionName;
23
+ }
24
+ }
25
+ /**
26
+ * Send a prompt to an ACP agent and wait for completion.
27
+ * Collects all stdout + stderr output and extracts the agent's response.
28
+ */
29
+ async prompt(agent, sessionName, text) {
30
+ const events = [];
31
+ return new Promise((resolve, reject) => {
32
+ // Use text format (default) — most reliable across acpx versions.
33
+ // --approve-all prevents interactive permission prompts from blocking.
34
+ const proc = spawn('acpx', ['--approve-all', agent, 'prompt', '-s', sessionName, text], {
35
+ stdio: ['pipe', 'pipe', 'pipe'],
36
+ cwd: this.cwd,
37
+ env: { ...process.env },
38
+ });
39
+ let stdout = '';
40
+ let stderr = '';
41
+ proc.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
42
+ proc.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
43
+ proc.on('close', (code) => {
44
+ // acpx text mode writes the agent's response to stdout.
45
+ // Try to extract meaningful output from stdout, falling back to stderr.
46
+ const output = stdout.trim() || stderr.trim();
47
+ if (code !== 0 && !output) {
48
+ reject(new Error(`acpx exited with code ${code}: ${stderr.trim()}`));
49
+ }
50
+ else {
51
+ resolve({ output, events });
52
+ }
53
+ });
54
+ proc.on('error', (err) => {
55
+ reject(new Error(`Failed to spawn acpx: ${err.message}. Is acpx installed?`));
56
+ });
57
+ });
58
+ }
59
+ /**
60
+ * Cancel the current operation in a session.
61
+ */
62
+ async cancel(agent, sessionName) {
63
+ await this.exec(agent, ['cancel', '-s', sessionName]);
64
+ }
65
+ /**
66
+ * Close a session.
67
+ */
68
+ async close(agent, sessionName) {
69
+ await this.exec(agent, ['sessions', 'close', sessionName]);
70
+ }
71
+ /**
72
+ * Execute an acpx command and return stdout.
73
+ */
74
+ exec(agent, args) {
75
+ return new Promise((resolve, reject) => {
76
+ const proc = spawn('acpx', ['--approve-all', agent, ...args], {
77
+ stdio: ['pipe', 'pipe', 'pipe'],
78
+ cwd: this.cwd,
79
+ env: { ...process.env },
80
+ });
81
+ let stdout = '';
82
+ let stderr = '';
83
+ proc.stdout.on('data', (chunk) => { stdout += chunk.toString(); });
84
+ proc.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
85
+ proc.on('close', (code) => {
86
+ if (code !== 0)
87
+ reject(new Error(`acpx ${agent} ${args.join(' ')} failed (${code}): ${stderr.trim()}`));
88
+ else
89
+ resolve(stdout);
90
+ });
91
+ proc.on('error', (err) => {
92
+ reject(new Error(`Failed to spawn acpx: ${err.message}`));
93
+ });
94
+ });
95
+ }
96
+ }
97
+ //# sourceMappingURL=acpx-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acpx-client.js","sourceRoot":"","sources":["../src/acpx-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { AgentConfig } from './config.js';
2
+ export interface AgentIdentity {
3
+ email: string;
4
+ jmapToken: string;
5
+ smtpPassword: string;
6
+ }
7
+ /**
8
+ * Bridges a single ACP agent to the AAMP network.
9
+ * Manages AAMP identity, ACP session, and task routing.
10
+ */
11
+ export declare class AgentBridge {
12
+ private readonly agentConfig;
13
+ private readonly aampHost;
14
+ private readonly rejectUnauthorized;
15
+ private client;
16
+ private acpx;
17
+ private identity;
18
+ private sessionName;
19
+ private processing;
20
+ private pollingFallback;
21
+ private transportMode;
22
+ constructor(agentConfig: AgentConfig, aampHost: string, rejectUnauthorized: boolean);
23
+ get name(): string;
24
+ get email(): string;
25
+ get isConnected(): boolean;
26
+ get isUsingPollingFallback(): boolean;
27
+ get isBusy(): boolean;
28
+ /**
29
+ * Start the bridge: resolve identity → connect AAMP → ensure ACP session.
30
+ */
31
+ start(): Promise<void>;
32
+ /**
33
+ * Stop the bridge.
34
+ */
35
+ stop(): void;
36
+ private normalizeEmail;
37
+ private isSenderAllowed;
38
+ /**
39
+ * Handle an incoming AAMP task by forwarding to the ACP agent.
40
+ */
41
+ private handleTask;
42
+ /**
43
+ * Resolve AAMP identity: load from credentials file or register new.
44
+ */
45
+ private resolveIdentity;
46
+ }
@@ -0,0 +1,278 @@
1
+ import { AampClient } from 'aamp-sdk';
2
+ import { AcpxClient } from './acpx-client.js';
3
+ import { buildPrompt, parseResponse } from './prompt-builder.js';
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
5
+ import { homedir } from 'node:os';
6
+ import { basename, dirname, join } from 'node:path';
7
+ function defaultCredentialsFile(name) {
8
+ return join(homedir(), '.acp-bridge', `.aamp-${name}.json`);
9
+ }
10
+ function resolveCredentialsFile(pathValue, name) {
11
+ const raw = pathValue?.trim();
12
+ if (!raw)
13
+ return defaultCredentialsFile(name);
14
+ if (raw === '~')
15
+ return homedir();
16
+ if (raw.startsWith('~/'))
17
+ return join(homedir(), raw.slice(2));
18
+ return raw;
19
+ }
20
+ /**
21
+ * Bridges a single ACP agent to the AAMP network.
22
+ * Manages AAMP identity, ACP session, and task routing.
23
+ */
24
+ export class AgentBridge {
25
+ agentConfig;
26
+ aampHost;
27
+ rejectUnauthorized;
28
+ client = null;
29
+ acpx;
30
+ identity = null;
31
+ sessionName;
32
+ processing = false;
33
+ pollingFallback = false;
34
+ transportMode = 'connecting';
35
+ constructor(agentConfig, aampHost, rejectUnauthorized) {
36
+ this.agentConfig = agentConfig;
37
+ this.aampHost = aampHost;
38
+ this.rejectUnauthorized = rejectUnauthorized;
39
+ this.acpx = new AcpxClient();
40
+ this.sessionName = `aamp-${agentConfig.name}`;
41
+ }
42
+ get name() { return this.agentConfig.name; }
43
+ get email() { return this.identity?.email ?? '(not registered)'; }
44
+ get isConnected() { return this.client?.isConnected() ?? false; }
45
+ get isUsingPollingFallback() { return this.pollingFallback || (this.client?.isUsingPollingFallback() ?? false); }
46
+ get isBusy() { return this.processing; }
47
+ /**
48
+ * Start the bridge: resolve identity → connect AAMP → ensure ACP session.
49
+ */
50
+ async start() {
51
+ // 1. Resolve AAMP identity
52
+ this.identity = await this.resolveIdentity();
53
+ console.log(`[${this.name}] AAMP identity: ${this.identity.email}`);
54
+ // 2. Create AAMP client
55
+ const smtpUrl = new URL(this.aampHost);
56
+ this.client = new AampClient({
57
+ email: this.identity.email,
58
+ jmapToken: this.identity.jmapToken,
59
+ jmapUrl: this.aampHost,
60
+ smtpHost: smtpUrl.hostname,
61
+ smtpPort: 587,
62
+ smtpPassword: this.identity.smtpPassword,
63
+ rejectUnauthorized: this.rejectUnauthorized,
64
+ });
65
+ // 3. Wire up task handler
66
+ this.client.on('task.dispatch', (task) => {
67
+ this.handleTask(task).catch((err) => {
68
+ console.error(`[${this.name}] Task ${task.taskId} failed: ${err.message}`);
69
+ });
70
+ });
71
+ this.client.on('connected', () => {
72
+ const usingPollingFallback = this.client?.isUsingPollingFallback() ?? false;
73
+ this.pollingFallback = usingPollingFallback;
74
+ if (usingPollingFallback) {
75
+ if (this.transportMode !== 'polling') {
76
+ console.warn(`[${this.name}] AAMP connected (polling fallback active)`);
77
+ }
78
+ this.transportMode = 'polling';
79
+ }
80
+ else {
81
+ const previousMode = this.transportMode;
82
+ this.transportMode = 'websocket';
83
+ if (previousMode === 'polling') {
84
+ console.log(`[${this.name}] AAMP WebSocket restored`);
85
+ }
86
+ else {
87
+ console.log(`[${this.name}] AAMP connected`);
88
+ }
89
+ }
90
+ });
91
+ this.client.on('disconnected', (reason) => {
92
+ const usingPollingFallback = this.client?.isUsingPollingFallback() ?? false;
93
+ this.pollingFallback = usingPollingFallback;
94
+ if (usingPollingFallback) {
95
+ if (this.transportMode !== 'polling') {
96
+ console.warn(`[${this.name}] AAMP WebSocket unavailable, using polling fallback: ${reason}`);
97
+ }
98
+ this.transportMode = 'polling';
99
+ }
100
+ else {
101
+ this.transportMode = 'disconnected';
102
+ console.warn(`[${this.name}] AAMP disconnected: ${reason}`);
103
+ }
104
+ });
105
+ this.client.on('error', (err) => {
106
+ if (err.message.includes('falling back to polling')) {
107
+ this.pollingFallback = true;
108
+ if (this.transportMode !== 'polling') {
109
+ console.warn(`[${this.name}] ${err.message}`);
110
+ this.transportMode = 'polling';
111
+ }
112
+ return;
113
+ }
114
+ if (this.transportMode === 'polling' && (err.message.includes('JMAP WebSocket handshake failed')
115
+ || err.message.includes('Failed to get JMAP session')
116
+ || err.message.includes('Polling fallback failed'))) {
117
+ return;
118
+ }
119
+ console.error(`[${this.name}] AAMP error: ${err.message}`);
120
+ });
121
+ // 4. Connect to AAMP
122
+ await this.client.connect();
123
+ // 5. Ensure ACP session
124
+ try {
125
+ await this.acpx.ensureSession(this.agentConfig.acpCommand, this.sessionName);
126
+ console.log(`[${this.name}] ACP session ready: ${this.sessionName}`);
127
+ }
128
+ catch (err) {
129
+ console.warn(`[${this.name}] ACP session setup deferred: ${err.message}`);
130
+ }
131
+ }
132
+ /**
133
+ * Stop the bridge.
134
+ */
135
+ stop() {
136
+ this.client?.disconnect();
137
+ this.client = null;
138
+ }
139
+ normalizeEmail(email) {
140
+ return email.trim().toLowerCase();
141
+ }
142
+ isSenderAllowed(sender) {
143
+ const whitelist = this.agentConfig.senderWhitelist;
144
+ if (!whitelist)
145
+ return true;
146
+ const normalizedSender = this.normalizeEmail(sender);
147
+ return whitelist.some((allowed) => this.normalizeEmail(allowed) === normalizedSender);
148
+ }
149
+ /**
150
+ * Handle an incoming AAMP task by forwarding to the ACP agent.
151
+ */
152
+ async handleTask(task) {
153
+ if (!this.client)
154
+ return;
155
+ console.log(`[${this.name}] <- task.dispatch ${task.taskId} "${task.title}" from=${task.from}`);
156
+ if (!this.isSenderAllowed(task.from)) {
157
+ console.warn(`[${this.name}] Rejecting task ${task.taskId} from non-whitelisted sender: ${task.from}`);
158
+ await this.client.sendResult({
159
+ to: task.from,
160
+ taskId: task.taskId,
161
+ status: 'rejected',
162
+ output: '',
163
+ errorMsg: 'Unauthorized sender: this bridge only accepts tasks from whitelisted email addresses.',
164
+ inReplyTo: task.messageId,
165
+ });
166
+ return;
167
+ }
168
+ this.processing = true;
169
+ try {
170
+ const prompt = buildPrompt(task);
171
+ const result = await this.acpx.prompt(this.agentConfig.acpCommand, this.sessionName, prompt);
172
+ const parsed = parseResponse(result.output);
173
+ if (parsed.isHelp) {
174
+ // Agent needs help
175
+ await this.client.sendHelp({
176
+ to: task.from,
177
+ taskId: task.taskId,
178
+ question: parsed.question ?? 'Agent needs more information',
179
+ blockedReason: 'ACP agent requested clarification',
180
+ suggestedOptions: [],
181
+ inReplyTo: task.messageId,
182
+ });
183
+ console.log(`[${this.name}] -> task.help ${task.taskId}`);
184
+ }
185
+ else {
186
+ // Collect file attachments referenced by the agent
187
+ const attachments = [];
188
+ for (const filepath of parsed.files) {
189
+ if (existsSync(filepath)) {
190
+ try {
191
+ attachments.push({
192
+ filename: basename(filepath),
193
+ contentType: 'application/octet-stream',
194
+ content: readFileSync(filepath),
195
+ });
196
+ console.log(`[${this.name}] Attaching file: ${filepath}`);
197
+ }
198
+ catch (err) {
199
+ console.warn(`[${this.name}] Failed to read file ${filepath}: ${err.message}`);
200
+ }
201
+ }
202
+ }
203
+ // Task completed
204
+ await this.client.sendResult({
205
+ to: task.from,
206
+ taskId: task.taskId,
207
+ status: 'completed',
208
+ output: parsed.output,
209
+ inReplyTo: task.messageId,
210
+ attachments: attachments.length > 0 ? attachments : undefined,
211
+ });
212
+ console.log(`[${this.name}] -> task.result ${task.taskId} completed${attachments.length ? ` (${attachments.length} attachment(s))` : ''}`);
213
+ }
214
+ }
215
+ catch (err) {
216
+ const errorMsg = err.message;
217
+ console.error(`[${this.name}] Task ${task.taskId} error: ${errorMsg}`);
218
+ try {
219
+ await this.client.sendResult({
220
+ to: task.from,
221
+ taskId: task.taskId,
222
+ status: 'rejected',
223
+ output: '',
224
+ errorMsg: `ACP agent error: ${errorMsg}`,
225
+ inReplyTo: task.messageId,
226
+ });
227
+ }
228
+ catch { /* best effort */ }
229
+ }
230
+ finally {
231
+ this.processing = false;
232
+ }
233
+ }
234
+ /**
235
+ * Resolve AAMP identity: load from credentials file or register new.
236
+ */
237
+ async resolveIdentity() {
238
+ const credFile = resolveCredentialsFile(this.agentConfig.credentialsFile, this.agentConfig.name);
239
+ // Try loading existing credentials
240
+ if (existsSync(credFile)) {
241
+ try {
242
+ const data = JSON.parse(readFileSync(credFile, 'utf-8'));
243
+ if (data.email && data.jmapToken && data.smtpPassword) {
244
+ return data;
245
+ }
246
+ }
247
+ catch { /* re-register */ }
248
+ }
249
+ // Self-register
250
+ const slug = this.agentConfig.slug ?? `${this.agentConfig.name}-bridge`;
251
+ const description = this.agentConfig.description ?? `${this.agentConfig.name} via ACP bridge`;
252
+ // Step 1: Register
253
+ const regRes = await fetch(`${this.aampHost}/api/nodes/self-register`, {
254
+ method: 'POST',
255
+ headers: { 'Content-Type': 'application/json' },
256
+ body: JSON.stringify({ slug, description }),
257
+ });
258
+ if (!regRes.ok)
259
+ throw new Error(`Registration failed: ${regRes.status} ${await regRes.text()}`);
260
+ const regData = await regRes.json();
261
+ // Step 2: Exchange code for credentials
262
+ const credRes = await fetch(`${this.aampHost}/api/nodes/credentials?code=${regData.registrationCode}`);
263
+ if (!credRes.ok)
264
+ throw new Error(`Credential exchange failed: ${credRes.status}`);
265
+ const creds = await credRes.json();
266
+ const identity = {
267
+ email: creds.email,
268
+ jmapToken: creds.jmap.token,
269
+ smtpPassword: creds.smtp.password,
270
+ };
271
+ // Persist credentials
272
+ mkdirSync(dirname(credFile), { recursive: true });
273
+ writeFileSync(credFile, JSON.stringify(identity, null, 2));
274
+ console.log(`[${this.name}] Registered: ${identity.email} (credentials saved to ${credFile})`);
275
+ return identity;
276
+ }
277
+ }
278
+ //# sourceMappingURL=agent-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-bridge.js","sourceRoot":"","sources":["../src/agent-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { BridgeConfig } from './config.js';
2
+ /**
3
+ * Manages multiple ACP agent bridges, each with its own AAMP identity.
4
+ */
5
+ export declare class AampAcpBridge {
6
+ private agents;
7
+ private config;
8
+ constructor(config: BridgeConfig);
9
+ /**
10
+ * Start all configured agents.
11
+ */
12
+ start(): Promise<void>;
13
+ /**
14
+ * Stop all agents.
15
+ */
16
+ stop(): void;
17
+ /**
18
+ * List all agents and their status.
19
+ */
20
+ list(): void;
21
+ }
package/dist/bridge.js ADDED
@@ -0,0 +1,66 @@
1
+ import { AgentBridge } from './agent-bridge.js';
2
+ /**
3
+ * Manages multiple ACP agent bridges, each with its own AAMP identity.
4
+ */
5
+ export class AampAcpBridge {
6
+ agents = new Map();
7
+ config;
8
+ constructor(config) {
9
+ this.config = config;
10
+ }
11
+ /**
12
+ * Start all configured agents.
13
+ */
14
+ async start() {
15
+ console.log(`\nAAMP ACP Bridge`);
16
+ console.log(` Host: ${this.config.aampHost}`);
17
+ console.log(` Agents: ${this.config.agents.length}\n`);
18
+ for (const agentConfig of this.config.agents) {
19
+ const bridge = new AgentBridge(agentConfig, this.config.aampHost, this.config.rejectUnauthorized);
20
+ try {
21
+ await bridge.start();
22
+ this.agents.set(agentConfig.name, bridge);
23
+ }
24
+ catch (err) {
25
+ console.error(`[${agentConfig.name}] Failed to start: ${err.message}`);
26
+ }
27
+ }
28
+ if (this.agents.size === 0) {
29
+ throw new Error('No agents started successfully');
30
+ }
31
+ console.log(`\nBridge running with ${this.agents.size} agent(s):`);
32
+ for (const [name, bridge] of this.agents) {
33
+ console.log(` ${name}: ${bridge.email}`);
34
+ }
35
+ console.log(`\nPress Ctrl+C to stop.\n`);
36
+ }
37
+ /**
38
+ * Stop all agents.
39
+ */
40
+ stop() {
41
+ for (const [name, bridge] of this.agents) {
42
+ console.log(`[${name}] Stopping...`);
43
+ bridge.stop();
44
+ }
45
+ this.agents.clear();
46
+ }
47
+ /**
48
+ * List all agents and their status.
49
+ */
50
+ list() {
51
+ if (this.agents.size === 0) {
52
+ console.log('No agents running.');
53
+ return;
54
+ }
55
+ console.log(`\nAgents (${this.agents.size}):`);
56
+ for (const [name, bridge] of this.agents) {
57
+ const status = bridge.isConnected
58
+ ? (bridge.isUsingPollingFallback ? 'connected (polling fallback)' : 'connected')
59
+ : 'disconnected';
60
+ const busy = bridge.isBusy ? ' (processing)' : '';
61
+ console.log(` ${name}: ${bridge.email} -- ${status}${busy}`);
62
+ }
63
+ console.log();
64
+ }
65
+ }
66
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runInit(configPath: string): Promise<void>;
@@ -0,0 +1,161 @@
1
+ import { createInterface } from 'node:readline';
2
+ import { writeFileSync, existsSync, mkdirSync } from 'node:fs';
3
+ import { execSync } from 'node:child_process';
4
+ import { homedir } from 'node:os';
5
+ import { dirname, join } from 'node:path';
6
+ const KNOWN_AGENTS = [
7
+ 'claude', 'codex', 'gemini', 'goose', 'openclaw',
8
+ 'opencode', 'cursor', 'copilot', 'kimi', 'kiro',
9
+ ];
10
+ function ask(rl, question) {
11
+ return new Promise((resolve) => rl.question(question, resolve));
12
+ }
13
+ function parseWhitelist(input) {
14
+ return input
15
+ .split(',')
16
+ .map((item) => item.trim().toLowerCase())
17
+ .filter(Boolean);
18
+ }
19
+ function detectAgent(name) {
20
+ try {
21
+ execSync(`which ${name}`, { stdio: 'pipe' });
22
+ try {
23
+ const version = execSync(`${name} --version 2>/dev/null || echo unknown`, { stdio: 'pipe' }).toString().trim().split('\n')[0];
24
+ return version;
25
+ }
26
+ catch {
27
+ return 'installed';
28
+ }
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ function defaultCredentialsFile(name) {
35
+ return join(homedir(), '.acp-bridge', `.aamp-${name}.json`);
36
+ }
37
+ export async function runInit(configPath) {
38
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
39
+ console.log('\nAAMP ACP Bridge Setup\n');
40
+ // 1. AAMP host
41
+ const aampHostInput = (await ask(rl, '? AAMP Service URL (default: https://meshmail.ai): ')).trim();
42
+ const aampHost = aampHostInput || 'https://meshmail.ai';
43
+ if (!aampHost) {
44
+ rl.close();
45
+ throw new Error('AAMP host is required');
46
+ }
47
+ // Verify connectivity
48
+ try {
49
+ const res = await fetch(`${aampHost}/health`);
50
+ if (res.ok) {
51
+ const data = await res.json();
52
+ console.log(` Connected (${data.service})\n`);
53
+ }
54
+ else {
55
+ console.log(` Warning: Server responded with ${res.status}\n`);
56
+ }
57
+ }
58
+ catch {
59
+ console.log(` Warning: Could not reach ${aampHost} -- continuing anyway\n`);
60
+ }
61
+ // 2. Scan for ACP agents
62
+ console.log('? Scanning for ACP agents...');
63
+ const detected = [];
64
+ for (const name of KNOWN_AGENTS) {
65
+ const version = detectAgent(name);
66
+ if (version) {
67
+ console.log(` + ${name.padEnd(12)} (${version})`);
68
+ detected.push({ name, version });
69
+ }
70
+ else {
71
+ console.log(` - ${name.padEnd(12)} (not installed)`);
72
+ }
73
+ }
74
+ console.log();
75
+ if (detected.length === 0) {
76
+ console.log('No ACP agents found. Install an agent first (e.g. npm i -g @anthropic-ai/claude-code).');
77
+ rl.close();
78
+ return;
79
+ }
80
+ // 3. Select agents
81
+ const selected = [];
82
+ for (const { name } of detected) {
83
+ const answer = await ask(rl, `? Bridge ${name}? (y/N): `);
84
+ if (answer.trim().toLowerCase() === 'y') {
85
+ selected.push(name);
86
+ }
87
+ }
88
+ if (selected.length === 0) {
89
+ console.log('No agents selected. Exiting.');
90
+ rl.close();
91
+ return;
92
+ }
93
+ // 4. Register AAMP identities
94
+ console.log('\n? Registering AAMP identities...');
95
+ const agents = [];
96
+ for (const name of selected) {
97
+ const slug = `${name}-bridge`;
98
+ const credFile = defaultCredentialsFile(name);
99
+ const whitelistAnswer = await ask(rl, `? Restrict ${name} to a sender whitelist? (y/N): `);
100
+ let senderWhitelist;
101
+ if (whitelistAnswer.trim().toLowerCase() === 'y') {
102
+ const whitelistInput = await ask(rl, `? Allowed sender emails for ${name} (comma-separated): `);
103
+ const parsed = parseWhitelist(whitelistInput);
104
+ if (parsed.length === 0) {
105
+ console.log(` Warning: no valid whitelist entries provided; ${name} will accept all senders.`);
106
+ }
107
+ else {
108
+ senderWhitelist = parsed;
109
+ }
110
+ }
111
+ if (existsSync(credFile)) {
112
+ console.log(` + ${name} -> using existing credentials (${credFile})`);
113
+ agents.push({ name, acpCommand: name, slug, credentialsFile: credFile, senderWhitelist });
114
+ continue;
115
+ }
116
+ try {
117
+ const regRes = await fetch(`${aampHost}/api/nodes/self-register`, {
118
+ method: 'POST',
119
+ headers: { 'Content-Type': 'application/json' },
120
+ body: JSON.stringify({ slug, description: `${name} via ACP bridge` }),
121
+ });
122
+ if (!regRes.ok)
123
+ throw new Error(`${regRes.status}`);
124
+ const regData = await regRes.json();
125
+ const credRes = await fetch(`${aampHost}/api/nodes/credentials?code=${regData.registrationCode}`);
126
+ if (!credRes.ok)
127
+ throw new Error(`Credential exchange: ${credRes.status}`);
128
+ const creds = await credRes.json();
129
+ mkdirSync(dirname(credFile), { recursive: true });
130
+ writeFileSync(credFile, JSON.stringify({
131
+ email: creds.email,
132
+ jmapToken: creds.jmap.token,
133
+ smtpPassword: creds.smtp.password,
134
+ }, null, 2));
135
+ console.log(` + ${name} -> ${creds.email}`);
136
+ agents.push({
137
+ name,
138
+ acpCommand: name,
139
+ slug,
140
+ credentialsFile: credFile,
141
+ description: `${name} via ACP bridge`,
142
+ senderWhitelist,
143
+ });
144
+ }
145
+ catch (err) {
146
+ console.log(` x ${name} -> registration failed: ${err.message}`);
147
+ }
148
+ }
149
+ if (agents.length === 0) {
150
+ console.log('No agents registered. Exiting.');
151
+ rl.close();
152
+ return;
153
+ }
154
+ // 5. Write config
155
+ const config = { aampHost, rejectUnauthorized: false, agents };
156
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
157
+ console.log(`\nConfig written to ${configPath}`);
158
+ console.log(` Run: npx --registry=https://bnpm.byted.org @byted-meego/aamp-acp-bridge start\n`);
159
+ rl.close();
160
+ }
161
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ import { z } from 'zod';
2
+ declare const agentConfigSchema: z.ZodObject<{
3
+ name: z.ZodString;
4
+ acpCommand: z.ZodString;
5
+ slug: z.ZodOptional<z.ZodString>;
6
+ description: z.ZodOptional<z.ZodString>;
7
+ credentialsFile: z.ZodOptional<z.ZodString>;
8
+ senderWhitelist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ name: string;
11
+ acpCommand: string;
12
+ slug?: string | undefined;
13
+ description?: string | undefined;
14
+ credentialsFile?: string | undefined;
15
+ senderWhitelist?: string[] | undefined;
16
+ }, {
17
+ name: string;
18
+ acpCommand: string;
19
+ slug?: string | undefined;
20
+ description?: string | undefined;
21
+ credentialsFile?: string | undefined;
22
+ senderWhitelist?: string[] | undefined;
23
+ }>;
24
+ declare const bridgeConfigSchema: z.ZodObject<{
25
+ aampHost: z.ZodString;
26
+ rejectUnauthorized: z.ZodDefault<z.ZodBoolean>;
27
+ agents: z.ZodArray<z.ZodObject<{
28
+ name: z.ZodString;
29
+ acpCommand: z.ZodString;
30
+ slug: z.ZodOptional<z.ZodString>;
31
+ description: z.ZodOptional<z.ZodString>;
32
+ credentialsFile: z.ZodOptional<z.ZodString>;
33
+ senderWhitelist: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
34
+ }, "strip", z.ZodTypeAny, {
35
+ name: string;
36
+ acpCommand: string;
37
+ slug?: string | undefined;
38
+ description?: string | undefined;
39
+ credentialsFile?: string | undefined;
40
+ senderWhitelist?: string[] | undefined;
41
+ }, {
42
+ name: string;
43
+ acpCommand: string;
44
+ slug?: string | undefined;
45
+ description?: string | undefined;
46
+ credentialsFile?: string | undefined;
47
+ senderWhitelist?: string[] | undefined;
48
+ }>, "many">;
49
+ }, "strip", z.ZodTypeAny, {
50
+ aampHost: string;
51
+ rejectUnauthorized: boolean;
52
+ agents: {
53
+ name: string;
54
+ acpCommand: string;
55
+ slug?: string | undefined;
56
+ description?: string | undefined;
57
+ credentialsFile?: string | undefined;
58
+ senderWhitelist?: string[] | undefined;
59
+ }[];
60
+ }, {
61
+ aampHost: string;
62
+ agents: {
63
+ name: string;
64
+ acpCommand: string;
65
+ slug?: string | undefined;
66
+ description?: string | undefined;
67
+ credentialsFile?: string | undefined;
68
+ senderWhitelist?: string[] | undefined;
69
+ }[];
70
+ rejectUnauthorized?: boolean | undefined;
71
+ }>;
72
+ export type AgentConfig = z.infer<typeof agentConfigSchema>;
73
+ export type BridgeConfig = z.infer<typeof bridgeConfigSchema>;
74
+ export declare function loadConfig(path: string): BridgeConfig;
75
+ export {};
package/dist/config.js ADDED
@@ -0,0 +1,23 @@
1
+ import { z } from 'zod';
2
+ import { readFileSync, existsSync } from 'node:fs';
3
+ const agentConfigSchema = z.object({
4
+ name: z.string().min(1),
5
+ acpCommand: z.string().min(1),
6
+ slug: z.string().regex(/^[a-z0-9-]+$/).optional(),
7
+ description: z.string().optional(),
8
+ credentialsFile: z.string().optional(),
9
+ senderWhitelist: z.array(z.string().email()).optional(),
10
+ });
11
+ const bridgeConfigSchema = z.object({
12
+ aampHost: z.string().url(),
13
+ rejectUnauthorized: z.boolean().default(false),
14
+ agents: z.array(agentConfigSchema).min(1),
15
+ });
16
+ export function loadConfig(path) {
17
+ if (!existsSync(path)) {
18
+ throw new Error(`Config file not found: ${path}. Run 'aamp-acp-bridge init' first.`);
19
+ }
20
+ const raw = JSON.parse(readFileSync(path, 'utf-8'));
21
+ return bridgeConfigSchema.parse(raw);
22
+ }
23
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAElD,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,QAAQ,EAAE;IACjD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACtC,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE;CACxD,CAAC,CAAA;AAEF,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC1B,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAC9C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAC1C,CAAC,CAAA;AAKF,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,qCAAqC,CAAC,CAAA;IACtF,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;IACnD,OAAO,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;AACtC,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { loadConfig } from './config.js';
6
+ import { AampAcpBridge } from './bridge.js';
7
+ import { runInit } from './cli/init.js';
8
+ const args = process.argv.slice(2);
9
+ const command = args[0] ?? 'start';
10
+ const configPath = args.includes('--config')
11
+ ? (args[args.indexOf('--config') + 1] ?? 'bridge.json')
12
+ : 'bridge.json';
13
+ function defaultCredentialsFile(name) {
14
+ return join(homedir(), '.acp-bridge', `.aamp-${name}.json`);
15
+ }
16
+ function resolveCredentialsFile(pathValue, name) {
17
+ const raw = pathValue?.trim();
18
+ if (!raw)
19
+ return defaultCredentialsFile(name);
20
+ if (raw === '~')
21
+ return homedir();
22
+ if (raw.startsWith('~/'))
23
+ return join(homedir(), raw.slice(2));
24
+ return raw;
25
+ }
26
+ async function main() {
27
+ switch (command) {
28
+ case 'init': {
29
+ await runInit(configPath);
30
+ break;
31
+ }
32
+ case 'start': {
33
+ const config = loadConfig(configPath);
34
+ const bridge = new AampAcpBridge(config);
35
+ // Graceful shutdown
36
+ const shutdown = () => {
37
+ console.log('\nShutting down...');
38
+ bridge.stop();
39
+ process.exit(0);
40
+ };
41
+ process.on('SIGTERM', shutdown);
42
+ process.on('SIGINT', shutdown);
43
+ await bridge.start();
44
+ // Keep alive
45
+ setInterval(() => { }, 60_000);
46
+ break;
47
+ }
48
+ case 'list': {
49
+ const config = loadConfig(configPath);
50
+ console.log(`\nConfigured agents (${config.agents.length}):`);
51
+ for (const a of config.agents) {
52
+ const credFile = resolveCredentialsFile(a.credentialsFile, a.name);
53
+ let email = '(not registered)';
54
+ try {
55
+ const creds = JSON.parse(readFileSync(credFile, 'utf-8'));
56
+ email = creds.email ?? email;
57
+ }
58
+ catch { /* no credentials yet */ }
59
+ console.log(` ${a.name}: ${email} (${a.acpCommand})`);
60
+ }
61
+ console.log();
62
+ break;
63
+ }
64
+ case 'status': {
65
+ const config = loadConfig(configPath);
66
+ const bridge = new AampAcpBridge(config);
67
+ await bridge.start();
68
+ bridge.list();
69
+ bridge.stop();
70
+ break;
71
+ }
72
+ case 'help':
73
+ default:
74
+ console.log(`
75
+ AAMP ACP Bridge -- Connect ACP agents to the AAMP email network
76
+
77
+ Usage:
78
+ aamp-acp-bridge init Interactive setup wizard
79
+ aamp-acp-bridge start [--config X] Start the bridge (default: bridge.json)
80
+ aamp-acp-bridge list [--config X] List configured agents
81
+ aamp-acp-bridge status Show live connection status
82
+ aamp-acp-bridge help Show this help
83
+
84
+ Examples:
85
+ npx --registry=https://bnpm.byted.org @byted-meego/aamp-acp-bridge init
86
+ npx --registry=https://bnpm.byted.org @byted-meego/aamp-acp-bridge start
87
+ npx --registry=https://bnpm.byted.org @byted-meego/aamp-acp-bridge start --config production.json
88
+ `);
89
+ break;
90
+ }
91
+ }
92
+ main().catch((err) => {
93
+ console.error(`Error: ${err.message}`);
94
+ process.exit(1);
95
+ });
96
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { TaskDispatch } from 'aamp-sdk';
2
+ /**
3
+ * Convert an AAMP TaskDispatch into a prompt string for an ACP agent.
4
+ */
5
+ export declare function buildPrompt(task: TaskDispatch): string;
6
+ /**
7
+ * Parse an ACP agent response to detect HELP requests and extract file paths.
8
+ * Returns { isHelp, question, output, files }.
9
+ */
10
+ export declare function parseResponse(output: string): {
11
+ isHelp: boolean;
12
+ question?: string;
13
+ output: string;
14
+ files: string[];
15
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Convert an AAMP TaskDispatch into a prompt string for an ACP agent.
3
+ */
4
+ export function buildPrompt(task) {
5
+ const parts = [
6
+ `## AAMP Task`,
7
+ ``,
8
+ `Task ID: ${task.taskId}`,
9
+ `From: ${task.from}`,
10
+ `Title: ${task.title}`,
11
+ ];
12
+ if (task.bodyText) {
13
+ parts.push(``, `Description:`, task.bodyText);
14
+ }
15
+ if (task.timeoutSecs) {
16
+ parts.push(``, `Deadline: ${task.timeoutSecs}s`);
17
+ }
18
+ parts.push(``, `Please complete this task and output your result directly.`, `If you cannot complete the task and need more information, start your response with "HELP:" followed by your question.`, ``, `If you create any files as part of this task, list each file path at the end of your response in this exact format:`, `FILE:/absolute/path/to/file`);
19
+ return parts.join('\n');
20
+ }
21
+ /**
22
+ * Parse an ACP agent response to detect HELP requests and extract file paths.
23
+ * Returns { isHelp, question, output, files }.
24
+ */
25
+ export function parseResponse(output) {
26
+ const trimmed = output.trim();
27
+ if (trimmed.startsWith('HELP:')) {
28
+ return {
29
+ isHelp: true,
30
+ question: trimmed.slice(5).trim(),
31
+ output: '',
32
+ files: [],
33
+ };
34
+ }
35
+ // Extract FILE: lines
36
+ const files = [];
37
+ const lines = trimmed.split('\n');
38
+ const outputLines = [];
39
+ for (const line of lines) {
40
+ if (line.startsWith('FILE:')) {
41
+ const path = line.slice(5).trim();
42
+ if (path)
43
+ files.push(path);
44
+ }
45
+ else {
46
+ outputLines.push(line);
47
+ }
48
+ }
49
+ return { isHelp: false, output: outputLines.join('\n').trim(), files };
50
+ }
51
+ //# sourceMappingURL=prompt-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-builder.js","sourceRoot":"","sources":["../src/prompt-builder.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,MAAM,KAAK,GAAG;QACZ,cAAc;QACd,EAAE;QACF,YAAY,IAAI,CAAC,MAAM,EAAE;QACzB,SAAS,IAAI,CAAC,IAAI,EAAE;QACpB,UAAU,IAAI,CAAC,KAAK,EAAE;KACvB,CAAA;IAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/C,CAAC;IAED,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,IAAI,CAAC,WAAW,GAAG,CAAC,CAAA;IAClD,CAAC;IAED,KAAK,CAAC,IAAI,CACR,EAAE,EACF,4DAA4D,EAC5D,wHAAwH,EACxH,EAAE,EACF,qHAAqH,EACrH,6BAA6B,CAC9B,CAAA;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAM1C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IAC7B,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,OAAO;YACL,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE;YACjC,MAAM,EAAE,EAAE;YACV,KAAK,EAAE,EAAE;SACV,CAAA;IACH,CAAC;IAED,sBAAsB;IACtB,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjC,MAAM,WAAW,GAAa,EAAE,CAAA;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;YACjC,IAAI,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5B,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAA;AACxE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "aamp-acp-bridge",
3
+ "files": [
4
+ "dist"
5
+ ],
6
+ "license": "MIT",
7
+ "version": "0.1.4",
8
+ "description": "Bridge ACP-compatible agents (Claude, Codex, Gemini, etc.) into the AAMP email network — zero code, config-driven",
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "bin": {
12
+ "aamp-acp-bridge": "dist/index.js"
13
+ },
14
+ "scripts": {
15
+ "dev": "tsx src/index.ts",
16
+ "build": "tsc",
17
+ "start": "node dist/index.js"
18
+ },
19
+ "dependencies": {
20
+ "aamp-sdk": "^0.1.0",
21
+ "zod": "^3.22.4"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.11.30",
25
+ "tsx": "^4.7.1",
26
+ "typescript": "^5.4.3"
27
+ },
28
+ "peerDependencies": {
29
+ "acpx": ">=0.1.0"
30
+ },
31
+ "peerDependenciesMeta": {
32
+ "acpx": { "optional": true }
33
+ }
34
+ }