@almyty/acp-server 1.0.5 → 1.0.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.js +48 -88
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49,136 +49,96 @@ if (!agentArg) {
|
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
51
|
// ── Main ─────────────────────────────────────────────────────────
|
|
52
|
-
async function
|
|
53
|
-
// Resolve credentials
|
|
52
|
+
async function resolveAgent(ref, send) {
|
|
54
53
|
const creds = resolveCredentials();
|
|
55
|
-
if (!creds)
|
|
56
|
-
|
|
57
|
-
'Set ALMYTY_TOKEN environment variable or run: npx @almyty/auth login\n');
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
54
|
+
if (!creds)
|
|
55
|
+
throw new Error('No auth token. Run: npx @almyty/auth login');
|
|
60
56
|
const proxy = new AlmytyProxy(creds.url, creds.token);
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const ref = agentArg;
|
|
68
|
-
const hasSlash = ref.includes('/');
|
|
69
|
-
const orgPrefix = hasSlash ? ref.split('/')[0] : undefined;
|
|
70
|
-
const agentRef = hasSlash ? ref.split('/').slice(1).join('/') : ref;
|
|
71
|
-
// 1. Try UUID direct lookup
|
|
72
|
-
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(agentRef);
|
|
73
|
-
if (isUUID) {
|
|
74
|
-
try {
|
|
75
|
-
const agent = await proxy.getAgent(agentRef);
|
|
76
|
-
agentId = agent.id;
|
|
77
|
-
process.stderr.write(`[acp] ${agent.name} (${agent.mode})\n`);
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
process.stderr.write(`Error: Agent not found: ${agentRef}\n`);
|
|
81
|
-
process.exit(1);
|
|
82
|
-
}
|
|
57
|
+
const agentRef = ref.includes('/') ? ref.split('/').slice(1).join('/') : ref;
|
|
58
|
+
// UUID
|
|
59
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(agentRef)) {
|
|
60
|
+
const a = await proxy.getAgent(agentRef);
|
|
61
|
+
process.stderr.write(`[acp] ${a.name} (${a.mode})\n`);
|
|
62
|
+
return new AlmytyAcpAgent(proxy, a.id, send);
|
|
83
63
|
}
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
agentId = match.id;
|
|
96
|
-
process.stderr.write(`[acp] ${match.name} (${match.mode})\n`);
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
const available = agents.map((a) => a.slug || a.name.toLowerCase().replace(/\s+/g, '-')).join(', ');
|
|
100
|
-
process.stderr.write(`Error: Agent "${ref}" not found.\nAvailable: ${available || '(none)'}\n`);
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
catch (err) {
|
|
105
|
-
process.stderr.write(`Error: Could not resolve agent "${ref}": ${err}\n`);
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
64
|
+
// Name/slug lookup
|
|
65
|
+
const agents = await proxy.listAgents();
|
|
66
|
+
const slugify = (s) => s.toLowerCase().replace(/\s+/g, '-');
|
|
67
|
+
const needle = slugify(agentRef);
|
|
68
|
+
const match = agents.find((a) => {
|
|
69
|
+
const aSlug = a.slug || slugify(a.name);
|
|
70
|
+
return aSlug === needle || a.name === agentRef || slugify(a.name) === needle;
|
|
71
|
+
});
|
|
72
|
+
if (match) {
|
|
73
|
+
process.stderr.write(`[acp] ${match.name} (${match.mode})\n`);
|
|
74
|
+
return new AlmytyAcpAgent(proxy, match.id, send);
|
|
108
75
|
}
|
|
109
|
-
|
|
76
|
+
const available = agents.map((a) => a.slug || slugify(a.name)).join(', ');
|
|
77
|
+
throw new Error(`Agent "${ref}" not found. Available: ${available || '(none)'}`);
|
|
78
|
+
}
|
|
79
|
+
async function main() {
|
|
80
|
+
// Send function: write ndjson to stdout
|
|
110
81
|
const send = (msg) => {
|
|
111
82
|
try {
|
|
112
|
-
|
|
113
|
-
process.stdout.write(line + '\n');
|
|
83
|
+
process.stdout.write(JSON.stringify(msg) + '\n');
|
|
114
84
|
}
|
|
115
85
|
catch (err) {
|
|
116
|
-
process.stderr.write(`[acp] Failed to serialize
|
|
86
|
+
process.stderr.write(`[acp] Failed to serialize: ${err}\n`);
|
|
117
87
|
}
|
|
118
88
|
};
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
terminal: false,
|
|
125
|
-
});
|
|
126
|
-
process.stderr.write(`[acp] Server ready. Listening for JSON-RPC messages on stdin.\n`);
|
|
89
|
+
// Start listening on stdin IMMEDIATELY — Zed expects the process
|
|
90
|
+
// to be ready for JSON-RPC as soon as it spawns. Agent resolution
|
|
91
|
+
// and auth happen lazily on first `initialize` message.
|
|
92
|
+
let agent = null;
|
|
93
|
+
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
127
94
|
rl.on('line', async (line) => {
|
|
128
|
-
// Skip empty lines
|
|
129
95
|
const trimmed = line.trim();
|
|
130
96
|
if (!trimmed)
|
|
131
97
|
return;
|
|
132
|
-
// Parse JSON-RPC message
|
|
133
98
|
let msg;
|
|
134
99
|
try {
|
|
135
100
|
msg = JSON.parse(trimmed);
|
|
136
101
|
}
|
|
137
102
|
catch {
|
|
138
|
-
|
|
139
|
-
send({
|
|
140
|
-
jsonrpc: '2.0',
|
|
141
|
-
id: null,
|
|
142
|
-
error: { code: -32700, message: 'Parse error: invalid JSON' },
|
|
143
|
-
});
|
|
103
|
+
send({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } });
|
|
144
104
|
return;
|
|
145
105
|
}
|
|
146
|
-
// Validate basic JSON-RPC structure
|
|
147
106
|
if (!msg.jsonrpc || msg.jsonrpc !== '2.0' || !msg.method) {
|
|
148
107
|
if (msg.id !== undefined) {
|
|
149
|
-
send({
|
|
150
|
-
jsonrpc: '2.0',
|
|
151
|
-
id: msg.id,
|
|
152
|
-
error: { code: -32600, message: 'Invalid JSON-RPC 2.0 request' },
|
|
153
|
-
});
|
|
108
|
+
send({ jsonrpc: '2.0', id: msg.id, error: { code: -32600, message: 'Invalid request' } });
|
|
154
109
|
}
|
|
155
110
|
return;
|
|
156
111
|
}
|
|
157
|
-
//
|
|
112
|
+
// Lazy init: resolve credentials + agent on first message
|
|
113
|
+
if (!agent) {
|
|
114
|
+
try {
|
|
115
|
+
agent = await resolveAgent(agentArg, send);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
send({ jsonrpc: '2.0', id: msg.id ?? null, error: { code: -32603, message: err.message } });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
158
122
|
try {
|
|
159
123
|
await agent.handleMessage(msg);
|
|
160
124
|
}
|
|
161
125
|
catch (err) {
|
|
162
|
-
process.stderr.write(`[acp]
|
|
126
|
+
process.stderr.write(`[acp] Error: ${err}\n`);
|
|
163
127
|
if (msg.id !== undefined && msg.id !== null) {
|
|
164
|
-
send({
|
|
165
|
-
jsonrpc: '2.0',
|
|
166
|
-
id: msg.id,
|
|
167
|
-
error: { code: -32603, message: 'Internal error' },
|
|
168
|
-
});
|
|
128
|
+
send({ jsonrpc: '2.0', id: msg.id, error: { code: -32603, message: 'Internal error' } });
|
|
169
129
|
}
|
|
170
130
|
}
|
|
171
131
|
});
|
|
172
132
|
// Handle stdin close (client disconnected)
|
|
173
133
|
rl.on('close', () => {
|
|
174
134
|
process.stderr.write('[acp] Client disconnected. Shutting down.\n');
|
|
175
|
-
agent
|
|
135
|
+
agent?.shutdown();
|
|
176
136
|
process.exit(0);
|
|
177
137
|
});
|
|
178
138
|
// Handle process signals
|
|
179
139
|
const shutdown = () => {
|
|
180
140
|
process.stderr.write('[acp] Shutting down.\n');
|
|
181
|
-
agent
|
|
141
|
+
agent?.shutdown();
|
|
182
142
|
process.exit(0);
|
|
183
143
|
};
|
|
184
144
|
process.on('SIGINT', shutdown);
|