@wolpertingerlabs/drawlatch 1.0.0-alpha.9.0 → 1.0.0-alpha.9.2
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 +28 -39
- package/bin/drawlatch.js +35 -101
- package/dist/remote/server.js +12 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,11 +108,11 @@ For custom setups (different aliases, multiple callers, different machines), you
|
|
|
108
108
|
**1. Generate keys:**
|
|
109
109
|
|
|
110
110
|
```bash
|
|
111
|
-
drawlatch generate-keys
|
|
112
|
-
drawlatch generate-keys
|
|
111
|
+
drawlatch generate-keys caller my-laptop
|
|
112
|
+
drawlatch generate-keys server
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
**2. Exchange public keys** — copy `*.pub.pem` files
|
|
115
|
+
**2. Exchange public keys** — on separate machines, copy `*.pub.pem` files to the matching `keys/callers/<alias>/` or `keys/server/` directory on the other machine. See [Key Exchange](#key-exchange) for details.
|
|
116
116
|
|
|
117
117
|
**3. Create configs** — copy the example files and edit:
|
|
118
118
|
|
|
@@ -165,7 +165,6 @@ Once connected, agents get these tools:
|
|
|
165
165
|
{
|
|
166
166
|
"host": "0.0.0.0",
|
|
167
167
|
"port": 9999,
|
|
168
|
-
"localKeysDir": "~/.drawlatch/keys/remote",
|
|
169
168
|
"connectors": [],
|
|
170
169
|
"callers": {},
|
|
171
170
|
"rateLimitPerMinute": 60
|
|
@@ -176,11 +175,12 @@ Once connected, agents get these tools:
|
|
|
176
175
|
|-------|-------------|---------|
|
|
177
176
|
| `host` | Network interface to bind | `127.0.0.1` |
|
|
178
177
|
| `port` | Listen port | `9999` |
|
|
179
|
-
| `localKeysDir` | Path to server's own keypair | `~/.drawlatch/keys/remote` |
|
|
180
178
|
| `connectors` | Custom connector definitions (see below) | `[]` |
|
|
181
179
|
| `callers` | Per-caller access control (see below) | `{}` |
|
|
182
180
|
| `rateLimitPerMinute` | Max requests per minute per session | `60` |
|
|
183
181
|
|
|
182
|
+
Server keys are always loaded from `keys/server/` inside the config directory.
|
|
183
|
+
|
|
184
184
|
### Callers
|
|
185
185
|
|
|
186
186
|
Each caller is identified by their public key and declares which connections they can access:
|
|
@@ -190,7 +190,6 @@ Each caller is identified by their public key and declares which connections the
|
|
|
190
190
|
"callers": {
|
|
191
191
|
"alice": {
|
|
192
192
|
"name": "Alice (senior engineer)",
|
|
193
|
-
"peerKeyDir": "~/.drawlatch/keys/peers/alice",
|
|
194
193
|
"connections": ["github", "stripe", "internal-api"],
|
|
195
194
|
"env": {
|
|
196
195
|
"GITHUB_TOKEN": "${ALICE_GITHUB_TOKEN}"
|
|
@@ -198,16 +197,16 @@ Each caller is identified by their public key and declares which connections the
|
|
|
198
197
|
},
|
|
199
198
|
"ci-server": {
|
|
200
199
|
"name": "GitHub Actions CI",
|
|
201
|
-
"peerKeyDir": "~/.drawlatch/keys/peers/ci-server",
|
|
202
200
|
"connections": ["github"]
|
|
203
201
|
}
|
|
204
202
|
}
|
|
205
203
|
}
|
|
206
204
|
```
|
|
207
205
|
|
|
206
|
+
Caller public keys are loaded automatically from `keys/callers/<alias>/` — no path configuration needed.
|
|
207
|
+
|
|
208
208
|
| Field | Required | Description |
|
|
209
209
|
|-------|----------|-------------|
|
|
210
|
-
| `peerKeyDir` | Yes | Path to this caller's public key files |
|
|
211
210
|
| `connections` | Yes | Array of connection names (built-in or custom connector aliases) |
|
|
212
211
|
| `name` | No | Human-readable name for audit logs |
|
|
213
212
|
| `env` | No | Per-caller env var overrides — redirect secret resolution per caller |
|
|
@@ -216,7 +215,9 @@ Each caller is identified by their public key and declares which connections the
|
|
|
216
215
|
The `env` map lets multiple callers share the same connection with different credentials:
|
|
217
216
|
- Keys are the env var names connectors reference (e.g., `GITHUB_TOKEN`)
|
|
218
217
|
- Values are `"${REAL_ENV_VAR}"` (redirect) or literal strings (direct injection)
|
|
219
|
-
- Checked before
|
|
218
|
+
- Checked before prefixed env vars during secret resolution
|
|
219
|
+
|
|
220
|
+
Without an explicit `env` mapping, secrets resolve via prefixed env vars (e.g., caller "alice" + `GITHUB_TOKEN` → `ALICE_GITHUB_TOKEN`).
|
|
220
221
|
|
|
221
222
|
### Custom Connectors
|
|
222
223
|
|
|
@@ -256,8 +257,6 @@ Used by the local MCP proxy to connect to the remote server:
|
|
|
256
257
|
```json
|
|
257
258
|
{
|
|
258
259
|
"remoteUrl": "http://127.0.0.1:9999",
|
|
259
|
-
"localKeyAlias": "my-laptop",
|
|
260
|
-
"remotePublicKeysDir": "~/.drawlatch/keys/peers/remote-server",
|
|
261
260
|
"connectTimeout": 10000,
|
|
262
261
|
"requestTimeout": 30000
|
|
263
262
|
}
|
|
@@ -266,13 +265,12 @@ Used by the local MCP proxy to connect to the remote server:
|
|
|
266
265
|
| Field | Description | Default |
|
|
267
266
|
|-------|-------------|---------|
|
|
268
267
|
| `remoteUrl` | URL of the remote server | `http://localhost:9999` |
|
|
269
|
-
| `localKeyAlias` | Key alias — resolved to `keys/local/<alias>/` | _(none)_ |
|
|
270
|
-
| `localKeysDir` | Explicit path to proxy's keypair (ignored when `localKeyAlias` is set) | `~/.drawlatch/keys/local/default` |
|
|
271
|
-
| `remotePublicKeysDir` | Path to remote server's public keys | `~/.drawlatch/keys/peers/remote-server` |
|
|
272
268
|
| `connectTimeout` | Handshake timeout (ms) | `10000` |
|
|
273
269
|
| `requestTimeout` | Request timeout (ms) | `30000` |
|
|
274
270
|
|
|
275
|
-
Key
|
|
271
|
+
Key paths are derived automatically — no configuration needed:
|
|
272
|
+
- Caller keys: `keys/callers/{MCP_KEY_ALIAS || "default"}/`
|
|
273
|
+
- Server public keys: `keys/server/`
|
|
276
274
|
|
|
277
275
|
### Advanced Configuration
|
|
278
276
|
|
|
@@ -337,40 +335,27 @@ See **[INGESTORS.md](INGESTORS.md)** for full configuration reference.
|
|
|
337
335
|
|
|
338
336
|
Remote mode requires mutual authentication via Ed25519/X25519 keypairs. Each identity gets four PEM files (signing + exchange, public + private). The `drawlatch init` command handles this automatically for single-machine setups.
|
|
339
337
|
|
|
340
|
-
For multi-machine setups, exchange public keys manually:
|
|
341
|
-
|
|
342
338
|
**Directory structure:**
|
|
343
339
|
|
|
344
340
|
```
|
|
345
341
|
~/.drawlatch/keys/
|
|
346
|
-
├──
|
|
347
|
-
├──
|
|
348
|
-
└──
|
|
349
|
-
|
|
350
|
-
└── remote-server/ # Server's public keys (on the proxy)
|
|
342
|
+
├── callers/
|
|
343
|
+
│ ├── default/ # Default caller keypair
|
|
344
|
+
│ └── alice/ # Additional caller keypair
|
|
345
|
+
└── server/ # Server keypair
|
|
351
346
|
```
|
|
352
347
|
|
|
353
|
-
|
|
348
|
+
Both sides (caller and server) store their keys in the same directory tree. On a single machine, `drawlatch init` generates both and they can authenticate immediately. On separate machines, copy the `*.pub.pem` files to the corresponding directory on the other machine.
|
|
354
349
|
|
|
355
|
-
|
|
356
|
-
# Proxy's public keys → server's peers directory
|
|
357
|
-
cp keys/local/my-laptop/signing.pub.pem keys/peers/my-laptop/signing.pub.pem
|
|
358
|
-
cp keys/local/my-laptop/exchange.pub.pem keys/peers/my-laptop/exchange.pub.pem
|
|
359
|
-
|
|
360
|
-
# Server's public keys → proxy's peers directory
|
|
361
|
-
cp keys/remote/signing.pub.pem keys/peers/remote-server/signing.pub.pem
|
|
362
|
-
cp keys/remote/exchange.pub.pem keys/peers/remote-server/exchange.pub.pem
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
If the proxy and server are on different machines, transfer only `*.pub.pem` files via `scp` or similar.
|
|
350
|
+
**Using [Callboard](https://github.com/WolpertingerLabs/callboard)?** Use `drawlatch sync` to exchange keys automatically via a double-code approval flow — no manual file copying needed.
|
|
366
351
|
|
|
367
352
|
### Multiple Agent Identities
|
|
368
353
|
|
|
369
354
|
Generate a keypair per agent and set `MCP_KEY_ALIAS` at spawn time:
|
|
370
355
|
|
|
371
356
|
```bash
|
|
372
|
-
drawlatch generate-keys
|
|
373
|
-
drawlatch generate-keys
|
|
357
|
+
drawlatch generate-keys caller alice
|
|
358
|
+
drawlatch generate-keys caller bob
|
|
374
359
|
```
|
|
375
360
|
|
|
376
361
|
```json
|
|
@@ -385,7 +370,7 @@ drawlatch generate-keys local bob
|
|
|
385
370
|
}
|
|
386
371
|
```
|
|
387
372
|
|
|
388
|
-
Register each agent as a separate caller
|
|
373
|
+
Register each agent as a separate caller in `remote.config.json`.
|
|
389
374
|
|
|
390
375
|
## CLI Reference
|
|
391
376
|
|
|
@@ -402,6 +387,7 @@ Commands:
|
|
|
402
387
|
config Show effective configuration and secret status
|
|
403
388
|
doctor Validate setup and diagnose issues
|
|
404
389
|
generate-keys Generate Ed25519 + X25519 keypairs
|
|
390
|
+
sync Exchange keys with a callboard instance
|
|
405
391
|
|
|
406
392
|
Options:
|
|
407
393
|
-h, --help Show help
|
|
@@ -422,10 +408,13 @@ Logs options:
|
|
|
422
408
|
--follow Tail the log output
|
|
423
409
|
|
|
424
410
|
Generate-keys subcommands:
|
|
425
|
-
|
|
426
|
-
|
|
411
|
+
caller [alias] Generate caller keypair (default alias: "default")
|
|
412
|
+
server Generate server keypair
|
|
427
413
|
show <path> Show fingerprint of existing keypair
|
|
428
414
|
--dir <path> Generate to custom directory
|
|
415
|
+
|
|
416
|
+
Sync options:
|
|
417
|
+
--ttl <seconds> Session timeout (default: 300)
|
|
429
418
|
```
|
|
430
419
|
|
|
431
420
|
## Library Usage (Local Mode)
|
package/bin/drawlatch.js
CHANGED
|
@@ -38,7 +38,7 @@ const { generateKeyBundle, saveKeyBundle, extractPublicKeys, fingerprint, loadKe
|
|
|
38
38
|
);
|
|
39
39
|
|
|
40
40
|
// Import connection template helpers
|
|
41
|
-
const { listConnectionTemplates
|
|
41
|
+
const { listConnectionTemplates } = await import(
|
|
42
42
|
join(PKG_ROOT, "dist/shared/connections.js")
|
|
43
43
|
);
|
|
44
44
|
|
|
@@ -80,8 +80,6 @@ try {
|
|
|
80
80
|
lines: { type: "string", short: "n", default: "50" },
|
|
81
81
|
follow: { type: "boolean", default: false },
|
|
82
82
|
path: { type: "boolean", default: false },
|
|
83
|
-
connections: { type: "string" },
|
|
84
|
-
alias: { type: "string" },
|
|
85
83
|
full: { type: "boolean", default: false },
|
|
86
84
|
ttl: { type: "string", default: "300" },
|
|
87
85
|
},
|
|
@@ -105,7 +103,10 @@ if (values.version) {
|
|
|
105
103
|
}
|
|
106
104
|
if (values.help && !subcommand) {
|
|
107
105
|
printHelp();
|
|
108
|
-
const latestVersion = await
|
|
106
|
+
const latestVersion = await Promise.race([
|
|
107
|
+
updateCheckPromise,
|
|
108
|
+
new Promise((r) => setTimeout(() => r(null), 100)),
|
|
109
|
+
]);
|
|
109
110
|
if (latestVersion) console.log(formatUpdateNotice(latestVersion));
|
|
110
111
|
process.exit(0);
|
|
111
112
|
}
|
|
@@ -187,7 +188,10 @@ switch (subcommand) {
|
|
|
187
188
|
case "help":
|
|
188
189
|
printHelp();
|
|
189
190
|
{
|
|
190
|
-
const latestVersion = await
|
|
191
|
+
const latestVersion = await Promise.race([
|
|
192
|
+
updateCheckPromise,
|
|
193
|
+
new Promise((r) => setTimeout(() => r(null), 100)),
|
|
194
|
+
]);
|
|
191
195
|
if (latestVersion) console.log(formatUpdateNotice(latestVersion));
|
|
192
196
|
}
|
|
193
197
|
break;
|
|
@@ -207,28 +211,15 @@ async function cmdDefault() {
|
|
|
207
211
|
console.log("Drawlatch remote server is not running.\n");
|
|
208
212
|
printHelp();
|
|
209
213
|
}
|
|
210
|
-
|
|
214
|
+
// Show update notice only if the check already resolved (don't block on network)
|
|
215
|
+
const latestVersion = await Promise.race([
|
|
216
|
+
updateCheckPromise,
|
|
217
|
+
new Promise((r) => setTimeout(() => r(null), 100)),
|
|
218
|
+
]);
|
|
211
219
|
if (latestVersion) console.log(formatUpdateNotice(latestVersion));
|
|
212
220
|
}
|
|
213
221
|
|
|
214
222
|
async function cmdInit() {
|
|
215
|
-
const alias = values.alias || "default";
|
|
216
|
-
const connectionsList = values.connections
|
|
217
|
-
? values.connections.split(",").map((c) => c.trim()).filter(Boolean)
|
|
218
|
-
: [];
|
|
219
|
-
|
|
220
|
-
// Validate requested connections exist
|
|
221
|
-
if (connectionsList.length > 0) {
|
|
222
|
-
const available = listAvailableConnections();
|
|
223
|
-
const availableSet = new Set(available);
|
|
224
|
-
const invalid = connectionsList.filter((c) => !availableSet.has(c));
|
|
225
|
-
if (invalid.length > 0) {
|
|
226
|
-
console.error(`Unknown connection(s): ${invalid.join(", ")}`);
|
|
227
|
-
console.error(`Available: ${available.join(", ")}`);
|
|
228
|
-
process.exit(1);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
223
|
console.log(`\nDrawlatch Setup`);
|
|
233
224
|
console.log(`===============\n`);
|
|
234
225
|
|
|
@@ -251,20 +242,7 @@ async function cmdInit() {
|
|
|
251
242
|
steps.push(`Server keys: CREATED (${fp})`);
|
|
252
243
|
}
|
|
253
244
|
|
|
254
|
-
// Step 3:
|
|
255
|
-
const callerKeysDir = join(getCallerKeysDir(), alias);
|
|
256
|
-
if (existsSync(join(callerKeysDir, "signing.key.pem"))) {
|
|
257
|
-
const existing = loadKeyBundle(callerKeysDir);
|
|
258
|
-
const fp = fingerprint(extractPublicKeys(existing));
|
|
259
|
-
steps.push(`Caller keys (${alias}): already exist (${fp})`);
|
|
260
|
-
} else {
|
|
261
|
-
const bundle = generateKeyBundle();
|
|
262
|
-
saveKeyBundle(bundle, callerKeysDir);
|
|
263
|
-
const fp = fingerprint(extractPublicKeys(bundle));
|
|
264
|
-
steps.push(`Caller keys (${alias}): CREATED (${fp})`);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Step 4: Scaffold proxy.config.json
|
|
245
|
+
// Step 3: Scaffold proxy.config.json
|
|
268
246
|
const proxyConfigPath = getProxyConfigPath();
|
|
269
247
|
if (existsSync(proxyConfigPath)) {
|
|
270
248
|
steps.push(`Proxy config: already exists`);
|
|
@@ -278,7 +256,7 @@ async function cmdInit() {
|
|
|
278
256
|
steps.push(`Proxy config: CREATED`);
|
|
279
257
|
}
|
|
280
258
|
|
|
281
|
-
// Step
|
|
259
|
+
// Step 4: Scaffold remote.config.json
|
|
282
260
|
const remoteConfigPath = getRemoteConfigPath();
|
|
283
261
|
if (existsSync(remoteConfigPath)) {
|
|
284
262
|
steps.push(`Remote config: already exists`);
|
|
@@ -287,44 +265,22 @@ async function cmdInit() {
|
|
|
287
265
|
host: "0.0.0.0",
|
|
288
266
|
port: 9999,
|
|
289
267
|
rateLimitPerMinute: 60,
|
|
290
|
-
callers: {
|
|
291
|
-
[alias]: {
|
|
292
|
-
name: alias === "default" ? "Default Caller" : alias,
|
|
293
|
-
connections: connectionsList,
|
|
294
|
-
},
|
|
295
|
-
},
|
|
268
|
+
callers: {},
|
|
296
269
|
};
|
|
297
270
|
writeFileSync(remoteConfigPath, JSON.stringify(remoteConfig, null, 2) + "\n", { mode: 0o600 });
|
|
298
|
-
steps.push(`Remote config: CREATED
|
|
271
|
+
steps.push(`Remote config: CREATED`);
|
|
299
272
|
}
|
|
300
273
|
|
|
301
|
-
// Step
|
|
274
|
+
// Step 5: Scaffold .env file
|
|
302
275
|
if (existsSync(ENV_FILE)) {
|
|
303
276
|
steps.push(`.env file: already exists`);
|
|
304
277
|
} else {
|
|
305
278
|
const envLines = [
|
|
306
279
|
"# Drawlatch environment secrets",
|
|
307
|
-
"#
|
|
280
|
+
"# Set tokens for your enabled connections",
|
|
281
|
+
"# Secrets are prefixed per caller (e.g., DEFAULT_GITHUB_TOKEN)",
|
|
308
282
|
"",
|
|
309
283
|
];
|
|
310
|
-
|
|
311
|
-
// Get secret info for requested connections (or all if none specified)
|
|
312
|
-
const templates = listConnectionTemplates();
|
|
313
|
-
const relevantTemplates = connectionsList.length > 0
|
|
314
|
-
? templates.filter((t) => connectionsList.includes(t.alias))
|
|
315
|
-
: templates.filter((t) => ["github", "slack", "discord-bot", "openai", "anthropic"].includes(t.alias));
|
|
316
|
-
|
|
317
|
-
for (const t of relevantTemplates) {
|
|
318
|
-
envLines.push(`# ${t.name}`);
|
|
319
|
-
for (const s of t.requiredSecrets) {
|
|
320
|
-
envLines.push(`# ${s}=`);
|
|
321
|
-
}
|
|
322
|
-
for (const s of t.optionalSecrets) {
|
|
323
|
-
envLines.push(`# ${s}=`);
|
|
324
|
-
}
|
|
325
|
-
envLines.push("");
|
|
326
|
-
}
|
|
327
|
-
|
|
328
284
|
writeFileSync(ENV_FILE, envLines.join("\n") + "\n", { mode: 0o600 });
|
|
329
285
|
steps.push(`.env file: CREATED`);
|
|
330
286
|
}
|
|
@@ -335,25 +291,10 @@ async function cmdInit() {
|
|
|
335
291
|
}
|
|
336
292
|
|
|
337
293
|
console.log(`\nSetup complete! Next steps:\n`);
|
|
338
|
-
|
|
339
|
-
if (connectionsList.length > 0) {
|
|
340
|
-
const templates = listConnectionTemplates();
|
|
341
|
-
const enabledTemplates = templates.filter((t) => connectionsList.includes(t.alias));
|
|
342
|
-
const allSecrets = enabledTemplates.flatMap((t) => t.requiredSecrets);
|
|
343
|
-
if (allSecrets.length > 0) {
|
|
344
|
-
console.log(` 1. Set your API secrets in ${ENV_FILE}:`);
|
|
345
|
-
for (const s of [...new Set(allSecrets)]) {
|
|
346
|
-
console.log(` ${s}=your_token_here`);
|
|
347
|
-
}
|
|
348
|
-
console.log();
|
|
349
|
-
}
|
|
350
|
-
} else {
|
|
351
|
-
console.log(` 1. Edit ${remoteConfigPath} to add connections (e.g., "github", "slack")`);
|
|
352
|
-
console.log(` Then set the required secrets in ${ENV_FILE}\n`);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
console.log(` 2. Start the remote server:`);
|
|
294
|
+
console.log(` 1. Start the remote server:`);
|
|
356
295
|
console.log(` drawlatch start\n`);
|
|
296
|
+
console.log(` 2. Add callers via key sync:`);
|
|
297
|
+
console.log(` drawlatch sync\n`);
|
|
357
298
|
console.log(` 3. Verify your setup:`);
|
|
358
299
|
console.log(` drawlatch doctor\n`);
|
|
359
300
|
}
|
|
@@ -869,14 +810,14 @@ async function cmdSync() {
|
|
|
869
810
|
console.log(
|
|
870
811
|
` Keys saved to: ${join(CONFIG_DIR, "keys", "callers", status.callerAlias)}/`,
|
|
871
812
|
);
|
|
872
|
-
console.log(
|
|
873
|
-
|
|
874
|
-
);
|
|
813
|
+
console.log(`\nThe caller can now connect (no server restart needed).`);
|
|
814
|
+
console.log(`\nTo grant API access, add connections in ${join(CONFIG_DIR, "remote.config.json")}:`);
|
|
875
815
|
console.log(` "callers": {`);
|
|
876
816
|
console.log(` "${status.callerAlias}": {`);
|
|
877
817
|
console.log(` "connections": ["github", "slack", ...]`);
|
|
878
818
|
console.log(` }`);
|
|
879
819
|
console.log(` }`);
|
|
820
|
+
console.log(`\nThen set the required secrets in ${ENV_FILE}`);
|
|
880
821
|
console.log();
|
|
881
822
|
process.exit(0);
|
|
882
823
|
}
|
|
@@ -1167,7 +1108,7 @@ drawlatch v${VERSION}
|
|
|
1167
1108
|
Usage: drawlatch [command] [options]
|
|
1168
1109
|
|
|
1169
1110
|
Commands:
|
|
1170
|
-
init Set up drawlatch (keys, config, .env)
|
|
1111
|
+
init Set up drawlatch server (keys, config, .env)
|
|
1171
1112
|
start Start the remote server (background by default)
|
|
1172
1113
|
stop Stop the background remote server
|
|
1173
1114
|
restart Restart the background remote server
|
|
@@ -1185,9 +1126,7 @@ Options:
|
|
|
1185
1126
|
Running 'drawlatch' with no arguments shows status (if running) or this help.
|
|
1186
1127
|
|
|
1187
1128
|
Examples:
|
|
1188
|
-
drawlatch init Set up
|
|
1189
|
-
drawlatch init --connections github Set up with GitHub connection
|
|
1190
|
-
drawlatch init --alias mybot Set up with custom caller alias
|
|
1129
|
+
drawlatch init Set up the remote server
|
|
1191
1130
|
drawlatch start Start remote server in background
|
|
1192
1131
|
drawlatch start -f Start remote server in foreground
|
|
1193
1132
|
drawlatch start -f --tunnel Start with a public tunnel for webhooks
|
|
@@ -1304,23 +1243,18 @@ function printInitHelp() {
|
|
|
1304
1243
|
console.log(`
|
|
1305
1244
|
drawlatch init
|
|
1306
1245
|
|
|
1307
|
-
Set up drawlatch
|
|
1308
|
-
files,
|
|
1246
|
+
Set up the drawlatch remote server. Generates server keys, creates
|
|
1247
|
+
config files, and scaffolds a .env template.
|
|
1248
|
+
|
|
1249
|
+
Callers are added separately via 'drawlatch sync' after the server
|
|
1250
|
+
is running.
|
|
1309
1251
|
|
|
1310
1252
|
Usage: drawlatch init [options]
|
|
1311
1253
|
|
|
1312
1254
|
Options:
|
|
1313
|
-
|
|
1314
|
-
--alias <name> Name for the local identity (default: "default")
|
|
1315
|
-
-h, --help Show this help message
|
|
1255
|
+
-h, --help Show this help message
|
|
1316
1256
|
|
|
1317
1257
|
All steps are idempotent — safe to re-run without overwriting existing files.
|
|
1318
|
-
|
|
1319
|
-
Examples:
|
|
1320
|
-
drawlatch init Set up with defaults
|
|
1321
|
-
drawlatch init --connections github Set up with GitHub enabled
|
|
1322
|
-
drawlatch init --alias laptop Use "laptop" as the caller alias
|
|
1323
|
-
drawlatch init --alias ci --connections github,slack
|
|
1324
1258
|
`);
|
|
1325
1259
|
}
|
|
1326
1260
|
|
package/dist/remote/server.js
CHANGED
|
@@ -1416,14 +1416,22 @@ export function main() {
|
|
|
1416
1416
|
}
|
|
1417
1417
|
const config = loadRemoteConfig();
|
|
1418
1418
|
const serverKeysDirPath = getServerKeysDir();
|
|
1419
|
-
|
|
1420
|
-
|
|
1419
|
+
const requiredKeyFiles = ['signing.key.pem', 'signing.pub.pem', 'exchange.key.pem', 'exchange.pub.pem'];
|
|
1420
|
+
const missingKeyFiles = requiredKeyFiles.filter((f) => !fs.existsSync(path.join(serverKeysDirPath, f)));
|
|
1421
|
+
if (missingKeyFiles.length > 0) {
|
|
1422
|
+
if (!fs.existsSync(serverKeysDirPath)) {
|
|
1423
|
+
console.error(`[remote] Error: Server keys not found at ${serverKeysDirPath}`);
|
|
1424
|
+
}
|
|
1425
|
+
else {
|
|
1426
|
+
console.error(`[remote] Error: Incomplete server keys in ${serverKeysDirPath}`);
|
|
1427
|
+
console.error(`[remote] Missing: ${missingKeyFiles.join(', ')}`);
|
|
1428
|
+
}
|
|
1421
1429
|
console.error('[remote] Run: drawlatch generate-keys server');
|
|
1422
1430
|
process.exit(1);
|
|
1423
1431
|
}
|
|
1424
1432
|
if (Object.keys(config.callers).length === 0) {
|
|
1425
|
-
console.
|
|
1426
|
-
console.
|
|
1433
|
+
console.log('[remote] No callers configured — server will accept sync requests.');
|
|
1434
|
+
console.log('[remote] To add callers, run: drawlatch sync');
|
|
1427
1435
|
}
|
|
1428
1436
|
const port = process.env.DRAWLATCH_PORT ? parseInt(process.env.DRAWLATCH_PORT, 10) : config.port;
|
|
1429
1437
|
const host = process.env.DRAWLATCH_HOST ?? config.host;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wolpertingerlabs/drawlatch",
|
|
3
|
-
"version": "1.0.0-alpha.9.
|
|
3
|
+
"version": "1.0.0-alpha.9.2",
|
|
4
4
|
"description": "Encrypted MCP proxy with mutual authentication. Local MCP server forwards requests through an encrypted channel to a remote secrets-holding server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/mcp/server.js",
|