@openape/nest 0.3.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/index.mjs +244 -1476
- package/package.json +1 -1
- package/dist/node-WKMHQLLZ-IJUWLHGB.mjs +0 -20
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import process3 from "process";
|
|
5
|
+
|
|
6
|
+
// src/lib/intent-channel.ts
|
|
7
|
+
import { readdirSync, readFileSync as readFileSync2, renameSync, statSync, unlinkSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, chmodSync } from "fs";
|
|
8
|
+
import { homedir as homedir2 } from "os";
|
|
9
|
+
import { join as join2 } from "path";
|
|
6
10
|
|
|
7
11
|
// src/api/agents.ts
|
|
8
12
|
import { execFile } from "child_process";
|
|
@@ -57,14 +61,6 @@ function removeAgent(name) {
|
|
|
57
61
|
// src/api/agents.ts
|
|
58
62
|
var execFileAsync = promisify(execFile);
|
|
59
63
|
var NAME_REGEX = /^[a-z][a-z0-9-]{0,23}$/;
|
|
60
|
-
function handleNestStatus(_ctx) {
|
|
61
|
-
return {
|
|
62
|
-
agents: listAgents().length
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
function handleAgentsList(_ctx) {
|
|
66
|
-
return { agents: listAgents() };
|
|
67
|
-
}
|
|
68
64
|
async function handleAgentSpawn(ctx) {
|
|
69
65
|
const body = ctx.body;
|
|
70
66
|
const name = typeof body?.name === "string" ? body.name : "";
|
|
@@ -99,6 +95,7 @@ async function handleAgentSpawn(ctx) {
|
|
|
99
95
|
} : void 0
|
|
100
96
|
};
|
|
101
97
|
upsertAgent(entry);
|
|
98
|
+
await ctx.supervisor.reconcile(listAgents());
|
|
102
99
|
return { name, email: entry.email, uid, home: entry.home };
|
|
103
100
|
}
|
|
104
101
|
async function handleAgentDestroy(ctx, name) {
|
|
@@ -109,6 +106,7 @@ async function handleAgentDestroy(ctx, name) {
|
|
|
109
106
|
const args = ["run", "--as", "root", "--", "apes", "agents", "destroy", name, "--force"];
|
|
110
107
|
await execFileAsync(ctx.apesBin, args, { maxBuffer: 4 * 1024 * 1024 });
|
|
111
108
|
removeAgent(name);
|
|
109
|
+
await ctx.supervisor.reconcile(listAgents());
|
|
112
110
|
return { name, removed: true };
|
|
113
111
|
}
|
|
114
112
|
async function readUidFromDscl(name) {
|
|
@@ -121,1514 +119,284 @@ async function readUidFromDscl(name) {
|
|
|
121
119
|
return -1;
|
|
122
120
|
}
|
|
123
121
|
|
|
124
|
-
// src/lib/
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
return encoded;
|
|
152
|
-
}
|
|
153
|
-
var decode = (input) => new Uint8Array(Buffer2.from(normalize(input), "base64url"));
|
|
154
|
-
|
|
155
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/util/errors.js
|
|
156
|
-
var JOSEError = class extends Error {
|
|
157
|
-
static code = "ERR_JOSE_GENERIC";
|
|
158
|
-
code = "ERR_JOSE_GENERIC";
|
|
159
|
-
constructor(message2, options) {
|
|
160
|
-
super(message2, options);
|
|
161
|
-
this.name = this.constructor.name;
|
|
162
|
-
Error.captureStackTrace?.(this, this.constructor);
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
var JWTClaimValidationFailed = class extends JOSEError {
|
|
166
|
-
static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
167
|
-
code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
168
|
-
claim;
|
|
169
|
-
reason;
|
|
170
|
-
payload;
|
|
171
|
-
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
172
|
-
super(message2, { cause: { claim, reason, payload } });
|
|
173
|
-
this.claim = claim;
|
|
174
|
-
this.reason = reason;
|
|
175
|
-
this.payload = payload;
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
var JWTExpired = class extends JOSEError {
|
|
179
|
-
static code = "ERR_JWT_EXPIRED";
|
|
180
|
-
code = "ERR_JWT_EXPIRED";
|
|
181
|
-
claim;
|
|
182
|
-
reason;
|
|
183
|
-
payload;
|
|
184
|
-
constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
|
|
185
|
-
super(message2, { cause: { claim, reason, payload } });
|
|
186
|
-
this.claim = claim;
|
|
187
|
-
this.reason = reason;
|
|
188
|
-
this.payload = payload;
|
|
189
|
-
}
|
|
190
|
-
};
|
|
191
|
-
var JOSEAlgNotAllowed = class extends JOSEError {
|
|
192
|
-
static code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
193
|
-
code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
194
|
-
};
|
|
195
|
-
var JOSENotSupported = class extends JOSEError {
|
|
196
|
-
static code = "ERR_JOSE_NOT_SUPPORTED";
|
|
197
|
-
code = "ERR_JOSE_NOT_SUPPORTED";
|
|
198
|
-
};
|
|
199
|
-
var JWSInvalid = class extends JOSEError {
|
|
200
|
-
static code = "ERR_JWS_INVALID";
|
|
201
|
-
code = "ERR_JWS_INVALID";
|
|
202
|
-
};
|
|
203
|
-
var JWTInvalid = class extends JOSEError {
|
|
204
|
-
static code = "ERR_JWT_INVALID";
|
|
205
|
-
code = "ERR_JWT_INVALID";
|
|
206
|
-
};
|
|
207
|
-
var JWKSInvalid = class extends JOSEError {
|
|
208
|
-
static code = "ERR_JWKS_INVALID";
|
|
209
|
-
code = "ERR_JWKS_INVALID";
|
|
210
|
-
};
|
|
211
|
-
var JWKSNoMatchingKey = class extends JOSEError {
|
|
212
|
-
static code = "ERR_JWKS_NO_MATCHING_KEY";
|
|
213
|
-
code = "ERR_JWKS_NO_MATCHING_KEY";
|
|
214
|
-
constructor(message2 = "no applicable key found in the JSON Web Key Set", options) {
|
|
215
|
-
super(message2, options);
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
var JWKSMultipleMatchingKeys = class extends JOSEError {
|
|
219
|
-
[Symbol.asyncIterator];
|
|
220
|
-
static code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
|
|
221
|
-
code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
|
|
222
|
-
constructor(message2 = "multiple matching keys found in the JSON Web Key Set", options) {
|
|
223
|
-
super(message2, options);
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
var JWKSTimeout = class extends JOSEError {
|
|
227
|
-
static code = "ERR_JWKS_TIMEOUT";
|
|
228
|
-
code = "ERR_JWKS_TIMEOUT";
|
|
229
|
-
constructor(message2 = "request timed out", options) {
|
|
230
|
-
super(message2, options);
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
var JWSSignatureVerificationFailed = class extends JOSEError {
|
|
234
|
-
static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
235
|
-
code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
236
|
-
constructor(message2 = "signature verification failed", options) {
|
|
237
|
-
super(message2, options);
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/is_key_object.js
|
|
242
|
-
import * as util from "util";
|
|
243
|
-
var is_key_object_default = (obj) => util.types.isKeyObject(obj);
|
|
244
|
-
|
|
245
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/webcrypto.js
|
|
246
|
-
import * as crypto2 from "crypto";
|
|
247
|
-
import * as util2 from "util";
|
|
248
|
-
var webcrypto2 = crypto2.webcrypto;
|
|
249
|
-
var webcrypto_default = webcrypto2;
|
|
250
|
-
var isCryptoKey = (key) => util2.types.isCryptoKey(key);
|
|
251
|
-
|
|
252
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/crypto_key.js
|
|
253
|
-
function unusable(name, prop = "algorithm.name") {
|
|
254
|
-
return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
255
|
-
}
|
|
256
|
-
function isAlgorithm(algorithm, name) {
|
|
257
|
-
return algorithm.name === name;
|
|
258
|
-
}
|
|
259
|
-
function getHashLength(hash) {
|
|
260
|
-
return parseInt(hash.name.slice(4), 10);
|
|
261
|
-
}
|
|
262
|
-
function getNamedCurve(alg) {
|
|
263
|
-
switch (alg) {
|
|
264
|
-
case "ES256":
|
|
265
|
-
return "P-256";
|
|
266
|
-
case "ES384":
|
|
267
|
-
return "P-384";
|
|
268
|
-
case "ES512":
|
|
269
|
-
return "P-521";
|
|
270
|
-
default:
|
|
271
|
-
throw new Error("unreachable");
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
function checkUsage(key, usages) {
|
|
275
|
-
if (usages.length && !usages.some((expected) => key.usages.includes(expected))) {
|
|
276
|
-
let msg = "CryptoKey does not support this operation, its usages must include ";
|
|
277
|
-
if (usages.length > 2) {
|
|
278
|
-
const last = usages.pop();
|
|
279
|
-
msg += `one of ${usages.join(", ")}, or ${last}.`;
|
|
280
|
-
} else if (usages.length === 2) {
|
|
281
|
-
msg += `one of ${usages[0]} or ${usages[1]}.`;
|
|
282
|
-
} else {
|
|
283
|
-
msg += `${usages[0]}.`;
|
|
284
|
-
}
|
|
285
|
-
throw new TypeError(msg);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
function checkSigCryptoKey(key, alg, ...usages) {
|
|
289
|
-
switch (alg) {
|
|
290
|
-
case "HS256":
|
|
291
|
-
case "HS384":
|
|
292
|
-
case "HS512": {
|
|
293
|
-
if (!isAlgorithm(key.algorithm, "HMAC"))
|
|
294
|
-
throw unusable("HMAC");
|
|
295
|
-
const expected = parseInt(alg.slice(2), 10);
|
|
296
|
-
const actual = getHashLength(key.algorithm.hash);
|
|
297
|
-
if (actual !== expected)
|
|
298
|
-
throw unusable(`SHA-${expected}`, "algorithm.hash");
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
|
-
case "RS256":
|
|
302
|
-
case "RS384":
|
|
303
|
-
case "RS512": {
|
|
304
|
-
if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5"))
|
|
305
|
-
throw unusable("RSASSA-PKCS1-v1_5");
|
|
306
|
-
const expected = parseInt(alg.slice(2), 10);
|
|
307
|
-
const actual = getHashLength(key.algorithm.hash);
|
|
308
|
-
if (actual !== expected)
|
|
309
|
-
throw unusable(`SHA-${expected}`, "algorithm.hash");
|
|
310
|
-
break;
|
|
311
|
-
}
|
|
312
|
-
case "PS256":
|
|
313
|
-
case "PS384":
|
|
314
|
-
case "PS512": {
|
|
315
|
-
if (!isAlgorithm(key.algorithm, "RSA-PSS"))
|
|
316
|
-
throw unusable("RSA-PSS");
|
|
317
|
-
const expected = parseInt(alg.slice(2), 10);
|
|
318
|
-
const actual = getHashLength(key.algorithm.hash);
|
|
319
|
-
if (actual !== expected)
|
|
320
|
-
throw unusable(`SHA-${expected}`, "algorithm.hash");
|
|
321
|
-
break;
|
|
322
|
-
}
|
|
323
|
-
case "EdDSA": {
|
|
324
|
-
if (key.algorithm.name !== "Ed25519" && key.algorithm.name !== "Ed448") {
|
|
325
|
-
throw unusable("Ed25519 or Ed448");
|
|
326
|
-
}
|
|
327
|
-
break;
|
|
328
|
-
}
|
|
329
|
-
case "Ed25519": {
|
|
330
|
-
if (!isAlgorithm(key.algorithm, "Ed25519"))
|
|
331
|
-
throw unusable("Ed25519");
|
|
332
|
-
break;
|
|
333
|
-
}
|
|
334
|
-
case "ES256":
|
|
335
|
-
case "ES384":
|
|
336
|
-
case "ES512": {
|
|
337
|
-
if (!isAlgorithm(key.algorithm, "ECDSA"))
|
|
338
|
-
throw unusable("ECDSA");
|
|
339
|
-
const expected = getNamedCurve(alg);
|
|
340
|
-
const actual = key.algorithm.namedCurve;
|
|
341
|
-
if (actual !== expected)
|
|
342
|
-
throw unusable(expected, "algorithm.namedCurve");
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
default:
|
|
346
|
-
throw new TypeError("CryptoKey does not support this operation");
|
|
347
|
-
}
|
|
348
|
-
checkUsage(key, usages);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/invalid_key_input.js
|
|
352
|
-
function message(msg, actual, ...types4) {
|
|
353
|
-
types4 = types4.filter(Boolean);
|
|
354
|
-
if (types4.length > 2) {
|
|
355
|
-
const last = types4.pop();
|
|
356
|
-
msg += `one of type ${types4.join(", ")}, or ${last}.`;
|
|
357
|
-
} else if (types4.length === 2) {
|
|
358
|
-
msg += `one of type ${types4[0]} or ${types4[1]}.`;
|
|
359
|
-
} else {
|
|
360
|
-
msg += `of type ${types4[0]}.`;
|
|
361
|
-
}
|
|
362
|
-
if (actual == null) {
|
|
363
|
-
msg += ` Received ${actual}`;
|
|
364
|
-
} else if (typeof actual === "function" && actual.name) {
|
|
365
|
-
msg += ` Received function ${actual.name}`;
|
|
366
|
-
} else if (typeof actual === "object" && actual != null) {
|
|
367
|
-
if (actual.constructor?.name) {
|
|
368
|
-
msg += ` Received an instance of ${actual.constructor.name}`;
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
return msg;
|
|
372
|
-
}
|
|
373
|
-
var invalid_key_input_default = (actual, ...types4) => {
|
|
374
|
-
return message("Key must be ", actual, ...types4);
|
|
375
|
-
};
|
|
376
|
-
function withAlg(alg, actual, ...types4) {
|
|
377
|
-
return message(`Key for the ${alg} algorithm must be `, actual, ...types4);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/is_key_like.js
|
|
381
|
-
var is_key_like_default = (key) => is_key_object_default(key) || isCryptoKey(key);
|
|
382
|
-
var types3 = ["KeyObject"];
|
|
383
|
-
if (globalThis.CryptoKey || webcrypto_default?.CryptoKey) {
|
|
384
|
-
types3.push("CryptoKey");
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/is_disjoint.js
|
|
388
|
-
var isDisjoint = (...headers) => {
|
|
389
|
-
const sources = headers.filter(Boolean);
|
|
390
|
-
if (sources.length === 0 || sources.length === 1) {
|
|
391
|
-
return true;
|
|
392
|
-
}
|
|
393
|
-
let acc;
|
|
394
|
-
for (const header of sources) {
|
|
395
|
-
const parameters = Object.keys(header);
|
|
396
|
-
if (!acc || acc.size === 0) {
|
|
397
|
-
acc = new Set(parameters);
|
|
398
|
-
continue;
|
|
399
|
-
}
|
|
400
|
-
for (const parameter of parameters) {
|
|
401
|
-
if (acc.has(parameter)) {
|
|
402
|
-
return false;
|
|
403
|
-
}
|
|
404
|
-
acc.add(parameter);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return true;
|
|
408
|
-
};
|
|
409
|
-
var is_disjoint_default = isDisjoint;
|
|
410
|
-
|
|
411
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/is_object.js
|
|
412
|
-
function isObjectLike(value) {
|
|
413
|
-
return typeof value === "object" && value !== null;
|
|
414
|
-
}
|
|
415
|
-
function isObject(input) {
|
|
416
|
-
if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") {
|
|
417
|
-
return false;
|
|
418
|
-
}
|
|
419
|
-
if (Object.getPrototypeOf(input) === null) {
|
|
420
|
-
return true;
|
|
421
|
-
}
|
|
422
|
-
let proto = input;
|
|
423
|
-
while (Object.getPrototypeOf(proto) !== null) {
|
|
424
|
-
proto = Object.getPrototypeOf(proto);
|
|
425
|
-
}
|
|
426
|
-
return Object.getPrototypeOf(input) === proto;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/get_named_curve.js
|
|
430
|
-
import { KeyObject } from "crypto";
|
|
431
|
-
|
|
432
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/is_jwk.js
|
|
433
|
-
function isJWK(key) {
|
|
434
|
-
return isObject(key) && typeof key.kty === "string";
|
|
435
|
-
}
|
|
436
|
-
function isPrivateJWK(key) {
|
|
437
|
-
return key.kty !== "oct" && typeof key.d === "string";
|
|
438
|
-
}
|
|
439
|
-
function isPublicJWK(key) {
|
|
440
|
-
return key.kty !== "oct" && typeof key.d === "undefined";
|
|
441
|
-
}
|
|
442
|
-
function isSecretJWK(key) {
|
|
443
|
-
return isJWK(key) && key.kty === "oct" && typeof key.k === "string";
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/get_named_curve.js
|
|
447
|
-
var namedCurveToJOSE = (namedCurve) => {
|
|
448
|
-
switch (namedCurve) {
|
|
449
|
-
case "prime256v1":
|
|
450
|
-
return "P-256";
|
|
451
|
-
case "secp384r1":
|
|
452
|
-
return "P-384";
|
|
453
|
-
case "secp521r1":
|
|
454
|
-
return "P-521";
|
|
455
|
-
case "secp256k1":
|
|
456
|
-
return "secp256k1";
|
|
457
|
-
default:
|
|
458
|
-
throw new JOSENotSupported("Unsupported key curve for this operation");
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
var getNamedCurve2 = (kee, raw) => {
|
|
462
|
-
let key;
|
|
463
|
-
if (isCryptoKey(kee)) {
|
|
464
|
-
key = KeyObject.from(kee);
|
|
465
|
-
} else if (is_key_object_default(kee)) {
|
|
466
|
-
key = kee;
|
|
467
|
-
} else if (isJWK(kee)) {
|
|
468
|
-
return kee.crv;
|
|
469
|
-
} else {
|
|
470
|
-
throw new TypeError(invalid_key_input_default(kee, ...types3));
|
|
471
|
-
}
|
|
472
|
-
if (key.type === "secret") {
|
|
473
|
-
throw new TypeError('only "private" or "public" type keys can be used for this operation');
|
|
474
|
-
}
|
|
475
|
-
switch (key.asymmetricKeyType) {
|
|
476
|
-
case "ed25519":
|
|
477
|
-
case "ed448":
|
|
478
|
-
return `Ed${key.asymmetricKeyType.slice(2)}`;
|
|
479
|
-
case "x25519":
|
|
480
|
-
case "x448":
|
|
481
|
-
return `X${key.asymmetricKeyType.slice(1)}`;
|
|
482
|
-
case "ec": {
|
|
483
|
-
const namedCurve = key.asymmetricKeyDetails.namedCurve;
|
|
484
|
-
if (raw) {
|
|
485
|
-
return namedCurve;
|
|
486
|
-
}
|
|
487
|
-
return namedCurveToJOSE(namedCurve);
|
|
122
|
+
// src/lib/intent-channel.ts
|
|
123
|
+
var POLL_MS = 1e3;
|
|
124
|
+
var INTENTS_DIR = join2(homedir2(), "intents");
|
|
125
|
+
var IntentChannel = class {
|
|
126
|
+
constructor(deps) {
|
|
127
|
+
this.deps = deps;
|
|
128
|
+
mkdirSync2(INTENTS_DIR, { recursive: true });
|
|
129
|
+
chmodSync(INTENTS_DIR, 504);
|
|
130
|
+
}
|
|
131
|
+
timer;
|
|
132
|
+
inflight = /* @__PURE__ */ new Set();
|
|
133
|
+
start() {
|
|
134
|
+
if (this.timer) return;
|
|
135
|
+
this.timer = setInterval(() => void this.tick(), POLL_MS);
|
|
136
|
+
this.deps.log(`intent-channel: polling ${INTENTS_DIR}`);
|
|
137
|
+
}
|
|
138
|
+
stop() {
|
|
139
|
+
if (this.timer) clearInterval(this.timer);
|
|
140
|
+
this.timer = void 0;
|
|
141
|
+
}
|
|
142
|
+
async tick() {
|
|
143
|
+
let entries;
|
|
144
|
+
try {
|
|
145
|
+
entries = readdirSync(INTENTS_DIR);
|
|
146
|
+
} catch {
|
|
147
|
+
return;
|
|
488
148
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/check_key_length.js
|
|
496
|
-
import { KeyObject as KeyObject2 } from "crypto";
|
|
497
|
-
var check_key_length_default = (key, alg) => {
|
|
498
|
-
let modulusLength;
|
|
499
|
-
try {
|
|
500
|
-
if (key instanceof KeyObject2) {
|
|
501
|
-
modulusLength = key.asymmetricKeyDetails?.modulusLength;
|
|
502
|
-
} else {
|
|
503
|
-
modulusLength = Buffer.from(key.n, "base64url").byteLength << 3;
|
|
149
|
+
for (const f of entries) {
|
|
150
|
+
if (!f.endsWith(".json")) continue;
|
|
151
|
+
if (this.inflight.has(f)) continue;
|
|
152
|
+
this.inflight.add(f);
|
|
153
|
+
void this.process(f).finally(() => this.inflight.delete(f));
|
|
504
154
|
}
|
|
505
|
-
} catch {
|
|
506
|
-
}
|
|
507
|
-
if (typeof modulusLength !== "number" || modulusLength < 2048) {
|
|
508
|
-
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/jwk_to_key.js
|
|
513
|
-
import { createPrivateKey, createPublicKey } from "crypto";
|
|
514
|
-
var parse = (key) => {
|
|
515
|
-
if (key.d) {
|
|
516
|
-
return createPrivateKey({ format: "jwk", key });
|
|
517
|
-
}
|
|
518
|
-
return createPublicKey({ format: "jwk", key });
|
|
519
|
-
};
|
|
520
|
-
var jwk_to_key_default = parse;
|
|
521
|
-
|
|
522
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/key/import.js
|
|
523
|
-
async function importJWK(jwk, alg) {
|
|
524
|
-
if (!isObject(jwk)) {
|
|
525
|
-
throw new TypeError("JWK must be an object");
|
|
526
155
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
156
|
+
async process(filename) {
|
|
157
|
+
const path = join2(INTENTS_DIR, filename);
|
|
158
|
+
let intent;
|
|
159
|
+
try {
|
|
160
|
+
const raw = readFileSync2(path, "utf8");
|
|
161
|
+
intent = JSON.parse(raw);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
this.deps.log(`intent-channel: failed to read ${filename}: ${err instanceof Error ? err.message : String(err)}`);
|
|
164
|
+
try {
|
|
165
|
+
unlinkSync(path);
|
|
166
|
+
} catch {
|
|
537
167
|
}
|
|
538
|
-
case "EC":
|
|
539
|
-
case "OKP":
|
|
540
|
-
return jwk_to_key_default({ ...jwk, alg });
|
|
541
|
-
default:
|
|
542
|
-
throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/check_key_type.js
|
|
547
|
-
var tag = (key) => key?.[Symbol.toStringTag];
|
|
548
|
-
var jwkMatchesOp = (alg, key, usage) => {
|
|
549
|
-
if (key.use !== void 0 && key.use !== "sig") {
|
|
550
|
-
throw new TypeError("Invalid key for this operation, when present its use must be sig");
|
|
551
|
-
}
|
|
552
|
-
if (key.key_ops !== void 0 && key.key_ops.includes?.(usage) !== true) {
|
|
553
|
-
throw new TypeError(`Invalid key for this operation, when present its key_ops must include ${usage}`);
|
|
554
|
-
}
|
|
555
|
-
if (key.alg !== void 0 && key.alg !== alg) {
|
|
556
|
-
throw new TypeError(`Invalid key for this operation, when present its alg must be ${alg}`);
|
|
557
|
-
}
|
|
558
|
-
return true;
|
|
559
|
-
};
|
|
560
|
-
var symmetricTypeCheck = (alg, key, usage, allowJwk) => {
|
|
561
|
-
if (key instanceof Uint8Array)
|
|
562
|
-
return;
|
|
563
|
-
if (allowJwk && isJWK(key)) {
|
|
564
|
-
if (isSecretJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
565
168
|
return;
|
|
566
|
-
throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`);
|
|
567
|
-
}
|
|
568
|
-
if (!is_key_like_default(key)) {
|
|
569
|
-
throw new TypeError(withAlg(alg, key, ...types3, "Uint8Array", allowJwk ? "JSON Web Key" : null));
|
|
570
|
-
}
|
|
571
|
-
if (key.type !== "secret") {
|
|
572
|
-
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
573
|
-
}
|
|
574
|
-
};
|
|
575
|
-
var asymmetricTypeCheck = (alg, key, usage, allowJwk) => {
|
|
576
|
-
if (allowJwk && isJWK(key)) {
|
|
577
|
-
switch (usage) {
|
|
578
|
-
case "sign":
|
|
579
|
-
if (isPrivateJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
580
|
-
return;
|
|
581
|
-
throw new TypeError(`JSON Web Key for this operation be a private JWK`);
|
|
582
|
-
case "verify":
|
|
583
|
-
if (isPublicJWK(key) && jwkMatchesOp(alg, key, usage))
|
|
584
|
-
return;
|
|
585
|
-
throw new TypeError(`JSON Web Key for this operation be a public JWK`);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
if (!is_key_like_default(key)) {
|
|
589
|
-
throw new TypeError(withAlg(alg, key, ...types3, allowJwk ? "JSON Web Key" : null));
|
|
590
|
-
}
|
|
591
|
-
if (key.type === "secret") {
|
|
592
|
-
throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
593
|
-
}
|
|
594
|
-
if (usage === "sign" && key.type === "public") {
|
|
595
|
-
throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`);
|
|
596
|
-
}
|
|
597
|
-
if (usage === "decrypt" && key.type === "public") {
|
|
598
|
-
throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`);
|
|
599
|
-
}
|
|
600
|
-
if (key.algorithm && usage === "verify" && key.type === "private") {
|
|
601
|
-
throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`);
|
|
602
|
-
}
|
|
603
|
-
if (key.algorithm && usage === "encrypt" && key.type === "private") {
|
|
604
|
-
throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`);
|
|
605
|
-
}
|
|
606
|
-
};
|
|
607
|
-
function checkKeyType(allowJwk, alg, key, usage) {
|
|
608
|
-
const symmetric = alg.startsWith("HS") || alg === "dir" || alg.startsWith("PBES2") || /^A\d{3}(?:GCM)?KW$/.test(alg);
|
|
609
|
-
if (symmetric) {
|
|
610
|
-
symmetricTypeCheck(alg, key, usage, allowJwk);
|
|
611
|
-
} else {
|
|
612
|
-
asymmetricTypeCheck(alg, key, usage, allowJwk);
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
var check_key_type_default = checkKeyType.bind(void 0, false);
|
|
616
|
-
var checkKeyTypeWithJwk = checkKeyType.bind(void 0, true);
|
|
617
|
-
|
|
618
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/validate_crit.js
|
|
619
|
-
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
620
|
-
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
|
|
621
|
-
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
622
|
-
}
|
|
623
|
-
if (!protectedHeader || protectedHeader.crit === void 0) {
|
|
624
|
-
return /* @__PURE__ */ new Set();
|
|
625
|
-
}
|
|
626
|
-
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) {
|
|
627
|
-
throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
|
|
628
|
-
}
|
|
629
|
-
let recognized;
|
|
630
|
-
if (recognizedOption !== void 0) {
|
|
631
|
-
recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
|
|
632
|
-
} else {
|
|
633
|
-
recognized = recognizedDefault;
|
|
634
|
-
}
|
|
635
|
-
for (const parameter of protectedHeader.crit) {
|
|
636
|
-
if (!recognized.has(parameter)) {
|
|
637
|
-
throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
638
|
-
}
|
|
639
|
-
if (joseHeader[parameter] === void 0) {
|
|
640
|
-
throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
641
|
-
}
|
|
642
|
-
if (recognized.get(parameter) && protectedHeader[parameter] === void 0) {
|
|
643
|
-
throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
644
169
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/verify.js
|
|
663
|
-
import * as crypto4 from "crypto";
|
|
664
|
-
import { promisify as promisify3 } from "util";
|
|
665
|
-
|
|
666
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/dsa_digest.js
|
|
667
|
-
function dsaDigest(alg) {
|
|
668
|
-
switch (alg) {
|
|
669
|
-
case "PS256":
|
|
670
|
-
case "RS256":
|
|
671
|
-
case "ES256":
|
|
672
|
-
case "ES256K":
|
|
673
|
-
return "sha256";
|
|
674
|
-
case "PS384":
|
|
675
|
-
case "RS384":
|
|
676
|
-
case "ES384":
|
|
677
|
-
return "sha384";
|
|
678
|
-
case "PS512":
|
|
679
|
-
case "RS512":
|
|
680
|
-
case "ES512":
|
|
681
|
-
return "sha512";
|
|
682
|
-
case "Ed25519":
|
|
683
|
-
case "EdDSA":
|
|
684
|
-
return void 0;
|
|
685
|
-
default:
|
|
686
|
-
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/node_key.js
|
|
691
|
-
import { constants, KeyObject as KeyObject3 } from "crypto";
|
|
692
|
-
var ecCurveAlgMap = /* @__PURE__ */ new Map([
|
|
693
|
-
["ES256", "P-256"],
|
|
694
|
-
["ES256K", "secp256k1"],
|
|
695
|
-
["ES384", "P-384"],
|
|
696
|
-
["ES512", "P-521"]
|
|
697
|
-
]);
|
|
698
|
-
function keyForCrypto(alg, key) {
|
|
699
|
-
let asymmetricKeyType;
|
|
700
|
-
let asymmetricKeyDetails;
|
|
701
|
-
let isJWK2;
|
|
702
|
-
if (key instanceof KeyObject3) {
|
|
703
|
-
asymmetricKeyType = key.asymmetricKeyType;
|
|
704
|
-
asymmetricKeyDetails = key.asymmetricKeyDetails;
|
|
705
|
-
} else {
|
|
706
|
-
isJWK2 = true;
|
|
707
|
-
switch (key.kty) {
|
|
708
|
-
case "RSA":
|
|
709
|
-
asymmetricKeyType = "rsa";
|
|
710
|
-
break;
|
|
711
|
-
case "EC":
|
|
712
|
-
asymmetricKeyType = "ec";
|
|
713
|
-
break;
|
|
714
|
-
case "OKP": {
|
|
715
|
-
if (key.crv === "Ed25519") {
|
|
716
|
-
asymmetricKeyType = "ed25519";
|
|
170
|
+
this.deps.log(`intent-channel: processing ${intent.action} (id=${intent.id})`);
|
|
171
|
+
let response;
|
|
172
|
+
try {
|
|
173
|
+
const ctx = {
|
|
174
|
+
url: new URL("intent:/"),
|
|
175
|
+
body: intent,
|
|
176
|
+
log: this.deps.log,
|
|
177
|
+
apesBin: this.deps.apesBin,
|
|
178
|
+
caller: "<intent-channel>",
|
|
179
|
+
grantId: intent.id,
|
|
180
|
+
supervisor: this.deps.supervisor
|
|
181
|
+
};
|
|
182
|
+
let result;
|
|
183
|
+
switch (intent.action) {
|
|
184
|
+
case "spawn":
|
|
185
|
+
result = await handleAgentSpawn(ctx);
|
|
717
186
|
break;
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
asymmetricKeyType = "ed448";
|
|
187
|
+
case "destroy":
|
|
188
|
+
result = await handleAgentDestroy(ctx, intent.name);
|
|
721
189
|
break;
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
let options;
|
|
730
|
-
switch (alg) {
|
|
731
|
-
case "Ed25519":
|
|
732
|
-
if (asymmetricKeyType !== "ed25519") {
|
|
733
|
-
throw new TypeError(`Invalid key for this operation, its asymmetricKeyType must be ed25519`);
|
|
734
|
-
}
|
|
735
|
-
break;
|
|
736
|
-
case "EdDSA":
|
|
737
|
-
if (!["ed25519", "ed448"].includes(asymmetricKeyType)) {
|
|
738
|
-
throw new TypeError("Invalid key for this operation, its asymmetricKeyType must be ed25519 or ed448");
|
|
739
|
-
}
|
|
740
|
-
break;
|
|
741
|
-
case "RS256":
|
|
742
|
-
case "RS384":
|
|
743
|
-
case "RS512":
|
|
744
|
-
if (asymmetricKeyType !== "rsa") {
|
|
745
|
-
throw new TypeError("Invalid key for this operation, its asymmetricKeyType must be rsa");
|
|
746
|
-
}
|
|
747
|
-
check_key_length_default(key, alg);
|
|
748
|
-
break;
|
|
749
|
-
case "PS256":
|
|
750
|
-
case "PS384":
|
|
751
|
-
case "PS512":
|
|
752
|
-
if (asymmetricKeyType === "rsa-pss") {
|
|
753
|
-
const { hashAlgorithm, mgf1HashAlgorithm, saltLength } = asymmetricKeyDetails;
|
|
754
|
-
const length = parseInt(alg.slice(-3), 10);
|
|
755
|
-
if (hashAlgorithm !== void 0 && (hashAlgorithm !== `sha${length}` || mgf1HashAlgorithm !== hashAlgorithm)) {
|
|
756
|
-
throw new TypeError(`Invalid key for this operation, its RSA-PSS parameters do not meet the requirements of "alg" ${alg}`);
|
|
757
|
-
}
|
|
758
|
-
if (saltLength !== void 0 && saltLength > length >> 3) {
|
|
759
|
-
throw new TypeError(`Invalid key for this operation, its RSA-PSS parameter saltLength does not meet the requirements of "alg" ${alg}`);
|
|
760
|
-
}
|
|
761
|
-
} else if (asymmetricKeyType !== "rsa") {
|
|
762
|
-
throw new TypeError("Invalid key for this operation, its asymmetricKeyType must be rsa or rsa-pss");
|
|
763
|
-
}
|
|
764
|
-
check_key_length_default(key, alg);
|
|
765
|
-
options = {
|
|
766
|
-
padding: constants.RSA_PKCS1_PSS_PADDING,
|
|
767
|
-
saltLength: constants.RSA_PSS_SALTLEN_DIGEST
|
|
768
|
-
};
|
|
769
|
-
break;
|
|
770
|
-
case "ES256":
|
|
771
|
-
case "ES256K":
|
|
772
|
-
case "ES384":
|
|
773
|
-
case "ES512": {
|
|
774
|
-
if (asymmetricKeyType !== "ec") {
|
|
775
|
-
throw new TypeError("Invalid key for this operation, its asymmetricKeyType must be ec");
|
|
776
|
-
}
|
|
777
|
-
const actual = get_named_curve_default(key);
|
|
778
|
-
const expected = ecCurveAlgMap.get(alg);
|
|
779
|
-
if (actual !== expected) {
|
|
780
|
-
throw new TypeError(`Invalid key curve for the algorithm, its curve must be ${expected}, got ${actual}`);
|
|
190
|
+
case "list":
|
|
191
|
+
result = { agents: listAgents() };
|
|
192
|
+
break;
|
|
193
|
+
default:
|
|
194
|
+
throw new Error(`unknown action: ${intent.action ?? "<undefined>"}`);
|
|
781
195
|
}
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/sign.js
|
|
795
|
-
import * as crypto3 from "crypto";
|
|
796
|
-
import { promisify as promisify2 } from "util";
|
|
797
|
-
|
|
798
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/hmac_digest.js
|
|
799
|
-
function hmacDigest(alg) {
|
|
800
|
-
switch (alg) {
|
|
801
|
-
case "HS256":
|
|
802
|
-
return "sha256";
|
|
803
|
-
case "HS384":
|
|
804
|
-
return "sha384";
|
|
805
|
-
case "HS512":
|
|
806
|
-
return "sha512";
|
|
807
|
-
default:
|
|
808
|
-
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/get_sign_verify_key.js
|
|
813
|
-
import { KeyObject as KeyObject4, createSecretKey } from "crypto";
|
|
814
|
-
function getSignVerifyKey(alg, key, usage) {
|
|
815
|
-
if (key instanceof Uint8Array) {
|
|
816
|
-
if (!alg.startsWith("HS")) {
|
|
817
|
-
throw new TypeError(invalid_key_input_default(key, ...types3));
|
|
818
|
-
}
|
|
819
|
-
return createSecretKey(key);
|
|
820
|
-
}
|
|
821
|
-
if (key instanceof KeyObject4) {
|
|
822
|
-
return key;
|
|
823
|
-
}
|
|
824
|
-
if (isCryptoKey(key)) {
|
|
825
|
-
checkSigCryptoKey(key, alg, usage);
|
|
826
|
-
return KeyObject4.from(key);
|
|
827
|
-
}
|
|
828
|
-
if (isJWK(key)) {
|
|
829
|
-
if (alg.startsWith("HS")) {
|
|
830
|
-
return createSecretKey(Buffer.from(key.k, "base64url"));
|
|
831
|
-
}
|
|
832
|
-
return key;
|
|
833
|
-
}
|
|
834
|
-
throw new TypeError(invalid_key_input_default(key, ...types3, "Uint8Array", "JSON Web Key"));
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/sign.js
|
|
838
|
-
var oneShotSign = promisify2(crypto3.sign);
|
|
839
|
-
var sign2 = async (alg, key, data) => {
|
|
840
|
-
const k = getSignVerifyKey(alg, key, "sign");
|
|
841
|
-
if (alg.startsWith("HS")) {
|
|
842
|
-
const hmac = crypto3.createHmac(hmacDigest(alg), k);
|
|
843
|
-
hmac.update(data);
|
|
844
|
-
return hmac.digest();
|
|
845
|
-
}
|
|
846
|
-
return oneShotSign(dsaDigest(alg), data, keyForCrypto(alg, k));
|
|
847
|
-
};
|
|
848
|
-
var sign_default = sign2;
|
|
849
|
-
|
|
850
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/verify.js
|
|
851
|
-
var oneShotVerify = promisify3(crypto4.verify);
|
|
852
|
-
var verify2 = async (alg, key, signature, data) => {
|
|
853
|
-
const k = getSignVerifyKey(alg, key, "verify");
|
|
854
|
-
if (alg.startsWith("HS")) {
|
|
855
|
-
const expected = await sign_default(alg, k, data);
|
|
856
|
-
const actual = signature;
|
|
196
|
+
response = { ok: true, result };
|
|
197
|
+
} catch (err) {
|
|
198
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
199
|
+
this.deps.log(`intent-channel: ${intent.action} failed: ${msg}`);
|
|
200
|
+
response = { ok: false, error: msg };
|
|
201
|
+
}
|
|
202
|
+
const respTmp = `${path.replace(/\.json$/, "")}.response.tmp`;
|
|
203
|
+
const respFinal = `${path.replace(/\.json$/, "")}.response`;
|
|
204
|
+
writeFileSync2(respTmp, `${JSON.stringify(response)}
|
|
205
|
+
`, { mode: 432 });
|
|
206
|
+
renameSync(respTmp, respFinal);
|
|
857
207
|
try {
|
|
858
|
-
|
|
208
|
+
unlinkSync(path);
|
|
859
209
|
} catch {
|
|
860
|
-
return false;
|
|
861
210
|
}
|
|
862
211
|
}
|
|
863
|
-
const algorithm = dsaDigest(alg);
|
|
864
|
-
const keyInput = keyForCrypto(alg, k);
|
|
865
|
-
try {
|
|
866
|
-
return await oneShotVerify(algorithm, data, keyInput, signature);
|
|
867
|
-
} catch {
|
|
868
|
-
return false;
|
|
869
|
-
}
|
|
870
212
|
};
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/jws/flattened/verify.js
|
|
874
|
-
async function flattenedVerify(jws, key, options) {
|
|
875
|
-
if (!isObject(jws)) {
|
|
876
|
-
throw new JWSInvalid("Flattened JWS must be an object");
|
|
877
|
-
}
|
|
878
|
-
if (jws.protected === void 0 && jws.header === void 0) {
|
|
879
|
-
throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members');
|
|
880
|
-
}
|
|
881
|
-
if (jws.protected !== void 0 && typeof jws.protected !== "string") {
|
|
882
|
-
throw new JWSInvalid("JWS Protected Header incorrect type");
|
|
883
|
-
}
|
|
884
|
-
if (jws.payload === void 0) {
|
|
885
|
-
throw new JWSInvalid("JWS Payload missing");
|
|
886
|
-
}
|
|
887
|
-
if (typeof jws.signature !== "string") {
|
|
888
|
-
throw new JWSInvalid("JWS Signature missing or incorrect type");
|
|
889
|
-
}
|
|
890
|
-
if (jws.header !== void 0 && !isObject(jws.header)) {
|
|
891
|
-
throw new JWSInvalid("JWS Unprotected Header incorrect type");
|
|
892
|
-
}
|
|
893
|
-
let parsedProt = {};
|
|
894
|
-
if (jws.protected) {
|
|
895
|
-
try {
|
|
896
|
-
const protectedHeader = decode(jws.protected);
|
|
897
|
-
parsedProt = JSON.parse(decoder.decode(protectedHeader));
|
|
898
|
-
} catch {
|
|
899
|
-
throw new JWSInvalid("JWS Protected Header is invalid");
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
if (!is_disjoint_default(parsedProt, jws.header)) {
|
|
903
|
-
throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
904
|
-
}
|
|
905
|
-
const joseHeader = {
|
|
906
|
-
...parsedProt,
|
|
907
|
-
...jws.header
|
|
908
|
-
};
|
|
909
|
-
const extensions = validate_crit_default(JWSInvalid, /* @__PURE__ */ new Map([["b64", true]]), options?.crit, parsedProt, joseHeader);
|
|
910
|
-
let b64 = true;
|
|
911
|
-
if (extensions.has("b64")) {
|
|
912
|
-
b64 = parsedProt.b64;
|
|
913
|
-
if (typeof b64 !== "boolean") {
|
|
914
|
-
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
const { alg } = joseHeader;
|
|
918
|
-
if (typeof alg !== "string" || !alg) {
|
|
919
|
-
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
920
|
-
}
|
|
921
|
-
const algorithms = options && validate_algorithms_default("algorithms", options.algorithms);
|
|
922
|
-
if (algorithms && !algorithms.has(alg)) {
|
|
923
|
-
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
924
|
-
}
|
|
925
|
-
if (b64) {
|
|
926
|
-
if (typeof jws.payload !== "string") {
|
|
927
|
-
throw new JWSInvalid("JWS Payload must be a string");
|
|
928
|
-
}
|
|
929
|
-
} else if (typeof jws.payload !== "string" && !(jws.payload instanceof Uint8Array)) {
|
|
930
|
-
throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
931
|
-
}
|
|
932
|
-
let resolvedKey = false;
|
|
933
|
-
if (typeof key === "function") {
|
|
934
|
-
key = await key(parsedProt, jws);
|
|
935
|
-
resolvedKey = true;
|
|
936
|
-
checkKeyTypeWithJwk(alg, key, "verify");
|
|
937
|
-
if (isJWK(key)) {
|
|
938
|
-
key = await importJWK(key, alg);
|
|
939
|
-
}
|
|
940
|
-
} else {
|
|
941
|
-
checkKeyTypeWithJwk(alg, key, "verify");
|
|
942
|
-
}
|
|
943
|
-
const data = concat(encoder.encode(jws.protected ?? ""), encoder.encode("."), typeof jws.payload === "string" ? encoder.encode(jws.payload) : jws.payload);
|
|
944
|
-
let signature;
|
|
213
|
+
function reapStaleResponses(log2) {
|
|
214
|
+
let entries;
|
|
945
215
|
try {
|
|
946
|
-
|
|
216
|
+
entries = readdirSync(INTENTS_DIR);
|
|
947
217
|
} catch {
|
|
948
|
-
|
|
949
|
-
}
|
|
950
|
-
const verified = await verify_default(alg, key, signature, data);
|
|
951
|
-
if (!verified) {
|
|
952
|
-
throw new JWSSignatureVerificationFailed();
|
|
218
|
+
return;
|
|
953
219
|
}
|
|
954
|
-
|
|
955
|
-
|
|
220
|
+
const now = Date.now();
|
|
221
|
+
for (const f of entries) {
|
|
222
|
+
if (!f.endsWith(".response")) continue;
|
|
223
|
+
const path = join2(INTENTS_DIR, f);
|
|
956
224
|
try {
|
|
957
|
-
|
|
225
|
+
const st = statSync(path);
|
|
226
|
+
if (now - st.mtimeMs > 60 * 60 * 1e3) {
|
|
227
|
+
unlinkSync(path);
|
|
228
|
+
log2(`intent-channel: reaped stale ${f}`);
|
|
229
|
+
}
|
|
958
230
|
} catch {
|
|
959
|
-
throw new JWSInvalid("Failed to base64url decode the payload");
|
|
960
|
-
}
|
|
961
|
-
} else if (typeof jws.payload === "string") {
|
|
962
|
-
payload = encoder.encode(jws.payload);
|
|
963
|
-
} else {
|
|
964
|
-
payload = jws.payload;
|
|
965
|
-
}
|
|
966
|
-
const result = { payload };
|
|
967
|
-
if (jws.protected !== void 0) {
|
|
968
|
-
result.protectedHeader = parsedProt;
|
|
969
|
-
}
|
|
970
|
-
if (jws.header !== void 0) {
|
|
971
|
-
result.unprotectedHeader = jws.header;
|
|
972
|
-
}
|
|
973
|
-
if (resolvedKey) {
|
|
974
|
-
return { ...result, key };
|
|
975
|
-
}
|
|
976
|
-
return result;
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/jws/compact/verify.js
|
|
980
|
-
async function compactVerify(jws, key, options) {
|
|
981
|
-
if (jws instanceof Uint8Array) {
|
|
982
|
-
jws = decoder.decode(jws);
|
|
983
|
-
}
|
|
984
|
-
if (typeof jws !== "string") {
|
|
985
|
-
throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
|
|
986
|
-
}
|
|
987
|
-
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
|
|
988
|
-
if (length !== 3) {
|
|
989
|
-
throw new JWSInvalid("Invalid Compact JWS");
|
|
990
|
-
}
|
|
991
|
-
const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options);
|
|
992
|
-
const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };
|
|
993
|
-
if (typeof key === "function") {
|
|
994
|
-
return { ...result, key: verified.key };
|
|
995
|
-
}
|
|
996
|
-
return result;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/epoch.js
|
|
1000
|
-
var epoch_default = (date) => Math.floor(date.getTime() / 1e3);
|
|
1001
|
-
|
|
1002
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/secs.js
|
|
1003
|
-
var minute = 60;
|
|
1004
|
-
var hour = minute * 60;
|
|
1005
|
-
var day = hour * 24;
|
|
1006
|
-
var week = day * 7;
|
|
1007
|
-
var year = day * 365.25;
|
|
1008
|
-
var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
1009
|
-
var secs_default = (str) => {
|
|
1010
|
-
const matched = REGEX.exec(str);
|
|
1011
|
-
if (!matched || matched[4] && matched[1]) {
|
|
1012
|
-
throw new TypeError("Invalid time period format");
|
|
1013
|
-
}
|
|
1014
|
-
const value = parseFloat(matched[2]);
|
|
1015
|
-
const unit = matched[3].toLowerCase();
|
|
1016
|
-
let numericDate;
|
|
1017
|
-
switch (unit) {
|
|
1018
|
-
case "sec":
|
|
1019
|
-
case "secs":
|
|
1020
|
-
case "second":
|
|
1021
|
-
case "seconds":
|
|
1022
|
-
case "s":
|
|
1023
|
-
numericDate = Math.round(value);
|
|
1024
|
-
break;
|
|
1025
|
-
case "minute":
|
|
1026
|
-
case "minutes":
|
|
1027
|
-
case "min":
|
|
1028
|
-
case "mins":
|
|
1029
|
-
case "m":
|
|
1030
|
-
numericDate = Math.round(value * minute);
|
|
1031
|
-
break;
|
|
1032
|
-
case "hour":
|
|
1033
|
-
case "hours":
|
|
1034
|
-
case "hr":
|
|
1035
|
-
case "hrs":
|
|
1036
|
-
case "h":
|
|
1037
|
-
numericDate = Math.round(value * hour);
|
|
1038
|
-
break;
|
|
1039
|
-
case "day":
|
|
1040
|
-
case "days":
|
|
1041
|
-
case "d":
|
|
1042
|
-
numericDate = Math.round(value * day);
|
|
1043
|
-
break;
|
|
1044
|
-
case "week":
|
|
1045
|
-
case "weeks":
|
|
1046
|
-
case "w":
|
|
1047
|
-
numericDate = Math.round(value * week);
|
|
1048
|
-
break;
|
|
1049
|
-
default:
|
|
1050
|
-
numericDate = Math.round(value * year);
|
|
1051
|
-
break;
|
|
1052
|
-
}
|
|
1053
|
-
if (matched[1] === "-" || matched[4] === "ago") {
|
|
1054
|
-
return -numericDate;
|
|
1055
|
-
}
|
|
1056
|
-
return numericDate;
|
|
1057
|
-
};
|
|
1058
|
-
|
|
1059
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/lib/jwt_claims_set.js
|
|
1060
|
-
var normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, "");
|
|
1061
|
-
var checkAudiencePresence = (audPayload, audOption) => {
|
|
1062
|
-
if (typeof audPayload === "string") {
|
|
1063
|
-
return audOption.includes(audPayload);
|
|
1064
|
-
}
|
|
1065
|
-
if (Array.isArray(audPayload)) {
|
|
1066
|
-
return audOption.some(Set.prototype.has.bind(new Set(audPayload)));
|
|
1067
|
-
}
|
|
1068
|
-
return false;
|
|
1069
|
-
};
|
|
1070
|
-
var jwt_claims_set_default = (protectedHeader, encodedPayload, options = {}) => {
|
|
1071
|
-
let payload;
|
|
1072
|
-
try {
|
|
1073
|
-
payload = JSON.parse(decoder.decode(encodedPayload));
|
|
1074
|
-
} catch {
|
|
1075
|
-
}
|
|
1076
|
-
if (!isObject(payload)) {
|
|
1077
|
-
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
1078
|
-
}
|
|
1079
|
-
const { typ } = options;
|
|
1080
|
-
if (typ && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
|
|
1081
|
-
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", "check_failed");
|
|
1082
|
-
}
|
|
1083
|
-
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
|
|
1084
|
-
const presenceCheck = [...requiredClaims];
|
|
1085
|
-
if (maxTokenAge !== void 0)
|
|
1086
|
-
presenceCheck.push("iat");
|
|
1087
|
-
if (audience !== void 0)
|
|
1088
|
-
presenceCheck.push("aud");
|
|
1089
|
-
if (subject !== void 0)
|
|
1090
|
-
presenceCheck.push("sub");
|
|
1091
|
-
if (issuer !== void 0)
|
|
1092
|
-
presenceCheck.push("iss");
|
|
1093
|
-
for (const claim of new Set(presenceCheck.reverse())) {
|
|
1094
|
-
if (!(claim in payload)) {
|
|
1095
|
-
throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
|
|
1096
231
|
}
|
|
1097
232
|
}
|
|
1098
|
-
if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
|
|
1099
|
-
throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, "iss", "check_failed");
|
|
1100
|
-
}
|
|
1101
|
-
if (subject && payload.sub !== subject) {
|
|
1102
|
-
throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, "sub", "check_failed");
|
|
1103
|
-
}
|
|
1104
|
-
if (audience && !checkAudiencePresence(payload.aud, typeof audience === "string" ? [audience] : audience)) {
|
|
1105
|
-
throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, "aud", "check_failed");
|
|
1106
|
-
}
|
|
1107
|
-
let tolerance;
|
|
1108
|
-
switch (typeof options.clockTolerance) {
|
|
1109
|
-
case "string":
|
|
1110
|
-
tolerance = secs_default(options.clockTolerance);
|
|
1111
|
-
break;
|
|
1112
|
-
case "number":
|
|
1113
|
-
tolerance = options.clockTolerance;
|
|
1114
|
-
break;
|
|
1115
|
-
case "undefined":
|
|
1116
|
-
tolerance = 0;
|
|
1117
|
-
break;
|
|
1118
|
-
default:
|
|
1119
|
-
throw new TypeError("Invalid clockTolerance option type");
|
|
1120
|
-
}
|
|
1121
|
-
const { currentDate } = options;
|
|
1122
|
-
const now = epoch_default(currentDate || /* @__PURE__ */ new Date());
|
|
1123
|
-
if ((payload.iat !== void 0 || maxTokenAge) && typeof payload.iat !== "number") {
|
|
1124
|
-
throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, "iat", "invalid");
|
|
1125
|
-
}
|
|
1126
|
-
if (payload.nbf !== void 0) {
|
|
1127
|
-
if (typeof payload.nbf !== "number") {
|
|
1128
|
-
throw new JWTClaimValidationFailed('"nbf" claim must be a number', payload, "nbf", "invalid");
|
|
1129
|
-
}
|
|
1130
|
-
if (payload.nbf > now + tolerance) {
|
|
1131
|
-
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", "check_failed");
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
if (payload.exp !== void 0) {
|
|
1135
|
-
if (typeof payload.exp !== "number") {
|
|
1136
|
-
throw new JWTClaimValidationFailed('"exp" claim must be a number', payload, "exp", "invalid");
|
|
1137
|
-
}
|
|
1138
|
-
if (payload.exp <= now - tolerance) {
|
|
1139
|
-
throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", "check_failed");
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
if (maxTokenAge) {
|
|
1143
|
-
const age = now - payload.iat;
|
|
1144
|
-
const max = typeof maxTokenAge === "number" ? maxTokenAge : secs_default(maxTokenAge);
|
|
1145
|
-
if (age - tolerance > max) {
|
|
1146
|
-
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", "check_failed");
|
|
1147
|
-
}
|
|
1148
|
-
if (age < 0 - tolerance) {
|
|
1149
|
-
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", "check_failed");
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
return payload;
|
|
1153
|
-
};
|
|
1154
|
-
|
|
1155
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/jwt/verify.js
|
|
1156
|
-
async function jwtVerify(jwt, key, options) {
|
|
1157
|
-
const verified = await compactVerify(jwt, key, options);
|
|
1158
|
-
if (verified.protectedHeader.crit?.includes("b64") && verified.protectedHeader.b64 === false) {
|
|
1159
|
-
throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
1160
|
-
}
|
|
1161
|
-
const payload = jwt_claims_set_default(verified.protectedHeader, verified.payload, options);
|
|
1162
|
-
const result = { payload, protectedHeader: verified.protectedHeader };
|
|
1163
|
-
if (typeof key === "function") {
|
|
1164
|
-
return { ...result, key: verified.key };
|
|
1165
|
-
}
|
|
1166
|
-
return result;
|
|
1167
233
|
}
|
|
1168
234
|
|
|
1169
|
-
//
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
}
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
if (
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
}
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
if (candidate && Array.isArray(jwk2.key_ops)) {
|
|
1219
|
-
candidate = jwk2.key_ops.includes("verify");
|
|
1220
|
-
}
|
|
1221
|
-
if (candidate) {
|
|
1222
|
-
switch (alg) {
|
|
1223
|
-
case "ES256":
|
|
1224
|
-
candidate = jwk2.crv === "P-256";
|
|
1225
|
-
break;
|
|
1226
|
-
case "ES256K":
|
|
1227
|
-
candidate = jwk2.crv === "secp256k1";
|
|
1228
|
-
break;
|
|
1229
|
-
case "ES384":
|
|
1230
|
-
candidate = jwk2.crv === "P-384";
|
|
1231
|
-
break;
|
|
1232
|
-
case "ES512":
|
|
1233
|
-
candidate = jwk2.crv === "P-521";
|
|
1234
|
-
break;
|
|
1235
|
-
case "Ed25519":
|
|
1236
|
-
candidate = jwk2.crv === "Ed25519";
|
|
1237
|
-
break;
|
|
1238
|
-
case "EdDSA":
|
|
1239
|
-
candidate = jwk2.crv === "Ed25519" || jwk2.crv === "Ed448";
|
|
1240
|
-
break;
|
|
1241
|
-
}
|
|
235
|
+
// src/lib/pm2-supervisor.ts
|
|
236
|
+
import { execFile as execFile2 } from "child_process";
|
|
237
|
+
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
238
|
+
import { join as join3 } from "path";
|
|
239
|
+
import process from "process";
|
|
240
|
+
import { promisify as promisify2 } from "util";
|
|
241
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
242
|
+
var AGENTS_DIR = "/var/openape/nest/agents";
|
|
243
|
+
function pm2AppName(agentName) {
|
|
244
|
+
return `openape-bridge-${agentName}`;
|
|
245
|
+
}
|
|
246
|
+
function ecosystemPath(agentName) {
|
|
247
|
+
return join3(AGENTS_DIR, agentName, "ecosystem.config.js");
|
|
248
|
+
}
|
|
249
|
+
function ecosystemContents(apesBin, agentName) {
|
|
250
|
+
void apesBin;
|
|
251
|
+
return `// Auto-generated by Pm2Supervisor for agent '${agentName}'.
|
|
252
|
+
// Edit at runtime via:
|
|
253
|
+
// apes run --as ${agentName} -- pm2 reload ${pm2AppName(agentName)}
|
|
254
|
+
module.exports = {
|
|
255
|
+
apps: [{
|
|
256
|
+
name: '${pm2AppName(agentName)}',
|
|
257
|
+
script: 'openape-chat-bridge',
|
|
258
|
+
autorestart: true,
|
|
259
|
+
max_restarts: 10,
|
|
260
|
+
min_uptime: '30s',
|
|
261
|
+
restart_delay: 2000,
|
|
262
|
+
merge_logs: true,
|
|
263
|
+
}],
|
|
264
|
+
}
|
|
265
|
+
`;
|
|
266
|
+
}
|
|
267
|
+
var Pm2Supervisor = class {
|
|
268
|
+
constructor(deps) {
|
|
269
|
+
this.deps = deps;
|
|
270
|
+
}
|
|
271
|
+
inflight = /* @__PURE__ */ new Set();
|
|
272
|
+
/** Bring per-agent pm2 state in line with the registry. Idempotent. */
|
|
273
|
+
async reconcile(desired) {
|
|
274
|
+
for (const agent of desired) {
|
|
275
|
+
if (agent.bridge == null) continue;
|
|
276
|
+
if (this.inflight.has(agent.name)) continue;
|
|
277
|
+
this.inflight.add(agent.name);
|
|
278
|
+
try {
|
|
279
|
+
await this.startOrReload(agent.name);
|
|
280
|
+
} catch (err) {
|
|
281
|
+
this.deps.log(`pm2-supervisor: ${agent.name} startOrReload failed: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
|
|
282
|
+
} finally {
|
|
283
|
+
this.inflight.delete(agent.name);
|
|
1242
284
|
}
|
|
1243
|
-
return candidate;
|
|
1244
|
-
});
|
|
1245
|
-
const { 0: jwk, length } = candidates;
|
|
1246
|
-
if (length === 0) {
|
|
1247
|
-
throw new JWKSNoMatchingKey();
|
|
1248
|
-
}
|
|
1249
|
-
if (length !== 1) {
|
|
1250
|
-
const error = new JWKSMultipleMatchingKeys();
|
|
1251
|
-
const { _cached } = this;
|
|
1252
|
-
error[Symbol.asyncIterator] = async function* () {
|
|
1253
|
-
for (const jwk2 of candidates) {
|
|
1254
|
-
try {
|
|
1255
|
-
yield await importWithAlgCache(_cached, jwk2, alg);
|
|
1256
|
-
} catch {
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
};
|
|
1260
|
-
throw error;
|
|
1261
285
|
}
|
|
1262
|
-
return importWithAlgCache(this._cached, jwk, alg);
|
|
1263
|
-
}
|
|
1264
|
-
};
|
|
1265
|
-
async function importWithAlgCache(cache, jwk, alg) {
|
|
1266
|
-
const cached = cache.get(jwk) || cache.set(jwk, {}).get(jwk);
|
|
1267
|
-
if (cached[alg] === void 0) {
|
|
1268
|
-
const key = await importJWK({ ...jwk, ext: true }, alg);
|
|
1269
|
-
if (key instanceof Uint8Array || key.type !== "public") {
|
|
1270
|
-
throw new JWKSInvalid("JSON Web Key Set members must be public keys");
|
|
1271
|
-
}
|
|
1272
|
-
cached[alg] = key;
|
|
1273
|
-
}
|
|
1274
|
-
return cached[alg];
|
|
1275
|
-
}
|
|
1276
|
-
function createLocalJWKSet(jwks) {
|
|
1277
|
-
const set = new LocalJWKSet(jwks);
|
|
1278
|
-
const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
|
|
1279
|
-
Object.defineProperties(localJWKSet, {
|
|
1280
|
-
jwks: {
|
|
1281
|
-
value: () => clone(set._jwks),
|
|
1282
|
-
enumerable: true,
|
|
1283
|
-
configurable: false,
|
|
1284
|
-
writable: false
|
|
1285
|
-
}
|
|
1286
|
-
});
|
|
1287
|
-
return localJWKSet;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
// ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/node/esm/runtime/fetch_jwks.js
|
|
1291
|
-
import * as http from "http";
|
|
1292
|
-
import * as https from "https";
|
|
1293
|
-
import { once } from "events";
|
|
1294
|
-
var fetchJwks = async (url, timeout, options) => {
|
|
1295
|
-
let get3;
|
|
1296
|
-
switch (url.protocol) {
|
|
1297
|
-
case "https:":
|
|
1298
|
-
get3 = https.get;
|
|
1299
|
-
break;
|
|
1300
|
-
case "http:":
|
|
1301
|
-
get3 = http.get;
|
|
1302
|
-
break;
|
|
1303
|
-
default:
|
|
1304
|
-
throw new TypeError("Unsupported URL protocol.");
|
|
1305
|
-
}
|
|
1306
|
-
const { agent, headers } = options;
|
|
1307
|
-
const req = get3(url.href, {
|
|
1308
|
-
agent,
|
|
1309
|
-
timeout,
|
|
1310
|
-
headers
|
|
1311
|
-
});
|
|
1312
|
-
const [response] = await Promise.race([once(req, "response"), once(req, "timeout")]);
|
|
1313
|
-
if (!response) {
|
|
1314
|
-
req.destroy();
|
|
1315
|
-
throw new JWKSTimeout();
|
|
1316
|
-
}
|
|
1317
|
-
if (response.statusCode !== 200) {
|
|
1318
|
-
throw new JOSEError("Expected 200 OK from the JSON Web Key Set HTTP response");
|
|
1319
|
-
}
|
|
1320
|
-
const parts = [];
|
|
1321
|
-
for await (const part of response) {
|
|
1322
|
-
parts.push(part);
|
|
1323
286
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
287
|
+
/** Stop one agent's pm2 app — used at destroy time. */
|
|
288
|
+
async stop(agentName) {
|
|
289
|
+
const name = pm2AppName(agentName);
|
|
290
|
+
try {
|
|
291
|
+
await this.runAsAgent(agentName, ["pm2", "delete", name]);
|
|
292
|
+
this.deps.log(`pm2-supervisor: deleted ${name}`);
|
|
293
|
+
} catch (err) {
|
|
294
|
+
this.deps.log(`pm2-supervisor: delete ${name}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/** Best-effort cleanup — called on Nest shutdown. We don't kill
|
|
298
|
+
* the per-agent pm2-daemons; they should keep running so bridges
|
|
299
|
+
* stay alive across Nest restarts. No-op for now. */
|
|
300
|
+
async stopAll() {
|
|
301
|
+
}
|
|
302
|
+
async startOrReload(agentName) {
|
|
303
|
+
const dir = join3(AGENTS_DIR, agentName);
|
|
304
|
+
mkdirSync3(dir, { recursive: true });
|
|
305
|
+
const path = ecosystemPath(agentName);
|
|
306
|
+
writeFileSync3(path, ecosystemContents(this.deps.apesBin, agentName), { mode: 420 });
|
|
307
|
+
await this.runAsAgent(agentName, ["pm2", "startOrReload", path]);
|
|
308
|
+
this.deps.log(`pm2-supervisor: ${agentName} bridge (re)started via pm2`);
|
|
309
|
+
}
|
|
310
|
+
/** Run a pm2 subcommand AS the agent — escapes-helper does the
|
|
311
|
+
* setuid switch, then exec's pm2 in the agent's uid. */
|
|
312
|
+
async runAsAgent(agentName, args) {
|
|
313
|
+
return execFileAsync2(
|
|
314
|
+
this.deps.apesBin,
|
|
315
|
+
["run", "--as", agentName, "--wait", "--", ...args],
|
|
316
|
+
{ maxBuffer: 1024 * 1024, env: process.env, timeout: 6e4 }
|
|
317
|
+
);
|
|
1328
318
|
}
|
|
1329
319
|
};
|
|
1330
|
-
var fetch_jwks_default = fetchJwks;
|
|
1331
320
|
|
|
1332
|
-
//
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
}
|
|
1336
|
-
var
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
return
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
_local;
|
|
1364
|
-
_cache;
|
|
1365
|
-
constructor(url, options) {
|
|
1366
|
-
if (!(url instanceof URL)) {
|
|
1367
|
-
throw new TypeError("url must be an instance of URL");
|
|
1368
|
-
}
|
|
1369
|
-
this._url = new URL(url.href);
|
|
1370
|
-
this._options = { agent: options?.agent, headers: options?.headers };
|
|
1371
|
-
this._timeoutDuration = typeof options?.timeoutDuration === "number" ? options?.timeoutDuration : 5e3;
|
|
1372
|
-
this._cooldownDuration = typeof options?.cooldownDuration === "number" ? options?.cooldownDuration : 3e4;
|
|
1373
|
-
this._cacheMaxAge = typeof options?.cacheMaxAge === "number" ? options?.cacheMaxAge : 6e5;
|
|
1374
|
-
if (options?.[jwksCache] !== void 0) {
|
|
1375
|
-
this._cache = options?.[jwksCache];
|
|
1376
|
-
if (isFreshJwksCache(options?.[jwksCache], this._cacheMaxAge)) {
|
|
1377
|
-
this._jwksTimestamp = this._cache.uat;
|
|
1378
|
-
this._local = createLocalJWKSet(this._cache.jwks);
|
|
321
|
+
// src/lib/troop-sync.ts
|
|
322
|
+
import { execFile as execFile3 } from "child_process";
|
|
323
|
+
import process2 from "process";
|
|
324
|
+
import { promisify as promisify3 } from "util";
|
|
325
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
326
|
+
var TICK_MS = 5 * 60 * 1e3;
|
|
327
|
+
var TroopSync = class {
|
|
328
|
+
constructor(deps) {
|
|
329
|
+
this.deps = deps;
|
|
330
|
+
}
|
|
331
|
+
timer;
|
|
332
|
+
inflight = false;
|
|
333
|
+
start() {
|
|
334
|
+
if (this.timer) return;
|
|
335
|
+
setTimeout(() => this.tick(), 3e4).unref();
|
|
336
|
+
this.timer = setInterval(() => this.tick(), TICK_MS);
|
|
337
|
+
this.deps.log("troop-sync: loop started (interval=5min)");
|
|
338
|
+
}
|
|
339
|
+
stop() {
|
|
340
|
+
if (this.timer) clearInterval(this.timer);
|
|
341
|
+
this.timer = void 0;
|
|
342
|
+
}
|
|
343
|
+
async tick() {
|
|
344
|
+
if (this.inflight) return;
|
|
345
|
+
this.inflight = true;
|
|
346
|
+
try {
|
|
347
|
+
const agents = listAgents();
|
|
348
|
+
if (agents.length === 0) return;
|
|
349
|
+
this.deps.log(`troop-sync: reconciling ${agents.length} agent(s)`);
|
|
350
|
+
for (const agent of agents) {
|
|
351
|
+
await this.syncOne(agent.name);
|
|
1379
352
|
}
|
|
353
|
+
} finally {
|
|
354
|
+
this.inflight = false;
|
|
1380
355
|
}
|
|
1381
356
|
}
|
|
1382
|
-
|
|
1383
|
-
return typeof this._jwksTimestamp === "number" ? Date.now() < this._jwksTimestamp + this._cooldownDuration : false;
|
|
1384
|
-
}
|
|
1385
|
-
fresh() {
|
|
1386
|
-
return typeof this._jwksTimestamp === "number" ? Date.now() < this._jwksTimestamp + this._cacheMaxAge : false;
|
|
1387
|
-
}
|
|
1388
|
-
async getKey(protectedHeader, token) {
|
|
1389
|
-
if (!this._local || !this.fresh()) {
|
|
1390
|
-
await this.reload();
|
|
1391
|
-
}
|
|
357
|
+
async syncOne(name) {
|
|
1392
358
|
try {
|
|
1393
|
-
|
|
359
|
+
await execFileAsync3(
|
|
360
|
+
this.deps.apesBin,
|
|
361
|
+
["run", "--as", name, "--wait", "--", "apes", "agents", "sync"],
|
|
362
|
+
{ maxBuffer: 1024 * 1024, env: process2.env, timeout: 6e4 }
|
|
363
|
+
);
|
|
1394
364
|
} catch (err) {
|
|
1395
|
-
|
|
1396
|
-
if (this.coolingDown() === false) {
|
|
1397
|
-
await this.reload();
|
|
1398
|
-
return this._local(protectedHeader, token);
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
throw err;
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
async reload() {
|
|
1405
|
-
if (this._pendingFetch && isCloudflareWorkers()) {
|
|
1406
|
-
this._pendingFetch = void 0;
|
|
1407
|
-
}
|
|
1408
|
-
const headers = new Headers(this._options.headers);
|
|
1409
|
-
if (USER_AGENT && !headers.has("User-Agent")) {
|
|
1410
|
-
headers.set("User-Agent", USER_AGENT);
|
|
1411
|
-
this._options.headers = Object.fromEntries(headers.entries());
|
|
365
|
+
this.deps.log(`troop-sync: ${name} failed: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
|
|
1412
366
|
}
|
|
1413
|
-
this._pendingFetch ||= fetch_jwks_default(this._url, this._timeoutDuration, this._options).then((json) => {
|
|
1414
|
-
this._local = createLocalJWKSet(json);
|
|
1415
|
-
if (this._cache) {
|
|
1416
|
-
this._cache.uat = Date.now();
|
|
1417
|
-
this._cache.jwks = json;
|
|
1418
|
-
}
|
|
1419
|
-
this._jwksTimestamp = Date.now();
|
|
1420
|
-
this._pendingFetch = void 0;
|
|
1421
|
-
}).catch((err) => {
|
|
1422
|
-
this._pendingFetch = void 0;
|
|
1423
|
-
throw err;
|
|
1424
|
-
});
|
|
1425
|
-
await this._pendingFetch;
|
|
1426
367
|
}
|
|
1427
368
|
};
|
|
1428
|
-
function createRemoteJWKSet(url, options) {
|
|
1429
|
-
const set = new RemoteJWKSet(url, options);
|
|
1430
|
-
const remoteJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
|
|
1431
|
-
Object.defineProperties(remoteJWKSet, {
|
|
1432
|
-
coolingDown: {
|
|
1433
|
-
get: () => set.coolingDown(),
|
|
1434
|
-
enumerable: true,
|
|
1435
|
-
configurable: false
|
|
1436
|
-
},
|
|
1437
|
-
fresh: {
|
|
1438
|
-
get: () => set.fresh(),
|
|
1439
|
-
enumerable: true,
|
|
1440
|
-
configurable: false
|
|
1441
|
-
},
|
|
1442
|
-
reload: {
|
|
1443
|
-
value: () => set.reload(),
|
|
1444
|
-
enumerable: true,
|
|
1445
|
-
configurable: false,
|
|
1446
|
-
writable: false
|
|
1447
|
-
},
|
|
1448
|
-
reloading: {
|
|
1449
|
-
get: () => !!set._pendingFetch,
|
|
1450
|
-
enumerable: true,
|
|
1451
|
-
configurable: false
|
|
1452
|
-
},
|
|
1453
|
-
jwks: {
|
|
1454
|
-
value: () => set._local?.jwks(),
|
|
1455
|
-
enumerable: true,
|
|
1456
|
-
configurable: false,
|
|
1457
|
-
writable: false
|
|
1458
|
-
}
|
|
1459
|
-
});
|
|
1460
|
-
return remoteJWKSet;
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
// ../../packages/core/dist/index.js
|
|
1464
|
-
var ALGORITHM = "EdDSA";
|
|
1465
|
-
async function verifyJWT(token, keyOrJWKS, options) {
|
|
1466
|
-
const verifyOptions = { algorithms: [ALGORITHM], ...options };
|
|
1467
|
-
const result = typeof keyOrJWKS === "function" ? await jwtVerify(token, keyOrJWKS, verifyOptions) : await jwtVerify(token, keyOrJWKS, verifyOptions);
|
|
1468
|
-
return result;
|
|
1469
|
-
}
|
|
1470
|
-
function createRemoteJWKS(jwksUri) {
|
|
1471
|
-
return createRemoteJWKSet(new URL(jwksUri));
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
// src/lib/auth.ts
|
|
1475
|
-
var NEST_AUDIENCE = "nest";
|
|
1476
|
-
var idpUrl = process.env.OPENAPE_IDP_URL ?? "https://id.openape.ai";
|
|
1477
|
-
var _jwks = null;
|
|
1478
|
-
function getJwks() {
|
|
1479
|
-
if (!_jwks) {
|
|
1480
|
-
const url = new URL("/.well-known/jwks.json", idpUrl).toString();
|
|
1481
|
-
_jwks = createRemoteJWKS(url);
|
|
1482
|
-
}
|
|
1483
|
-
return _jwks;
|
|
1484
|
-
}
|
|
1485
|
-
var NestAuthError = class extends Error {
|
|
1486
|
-
constructor(status, title) {
|
|
1487
|
-
super(title);
|
|
1488
|
-
this.status = status;
|
|
1489
|
-
this.title = title;
|
|
1490
|
-
}
|
|
1491
|
-
};
|
|
1492
|
-
async function verifyNestGrant(token, expectedCommand) {
|
|
1493
|
-
let claims;
|
|
1494
|
-
try {
|
|
1495
|
-
const result = await verifyJWT(token, getJwks(), {
|
|
1496
|
-
issuer: idpUrl,
|
|
1497
|
-
audience: NEST_AUDIENCE
|
|
1498
|
-
});
|
|
1499
|
-
claims = result.payload;
|
|
1500
|
-
} catch (err) {
|
|
1501
|
-
throw new NestAuthError(401, `Invalid or expired grant token: ${err instanceof Error ? err.message : String(err)}`);
|
|
1502
|
-
}
|
|
1503
|
-
if (typeof claims.sub !== "string" || !claims.sub) {
|
|
1504
|
-
throw new NestAuthError(401, "Grant token missing sub claim");
|
|
1505
|
-
}
|
|
1506
|
-
if (claims.target_host !== hostname()) {
|
|
1507
|
-
throw new NestAuthError(403, `Grant target_host (${claims.target_host}) does not match this nest (${hostname()})`);
|
|
1508
|
-
}
|
|
1509
|
-
const cmd = claims.command ?? [];
|
|
1510
|
-
if (cmd.length !== expectedCommand.length || cmd.some((c, i) => c !== expectedCommand[i])) {
|
|
1511
|
-
throw new NestAuthError(
|
|
1512
|
-
403,
|
|
1513
|
-
`Grant command (${JSON.stringify(cmd)}) does not match this route (${JSON.stringify(expectedCommand)})`
|
|
1514
|
-
);
|
|
1515
|
-
}
|
|
1516
|
-
return { caller: claims.sub, grantId: claims.grant_id, command: cmd };
|
|
1517
|
-
}
|
|
1518
|
-
async function primeJwksCache(log2) {
|
|
1519
|
-
try {
|
|
1520
|
-
await verifyJWT("eyJhbGciOiJFZERTQSJ9.e30.invalid", getJwks(), {}).catch(() => {
|
|
1521
|
-
});
|
|
1522
|
-
log2(`nest: JWKS primed from ${idpUrl}/.well-known/jwks.json`);
|
|
1523
|
-
} catch (err) {
|
|
1524
|
-
log2(`nest: warning \u2014 JWKS prime failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
369
|
|
|
1528
370
|
// src/index.ts
|
|
1529
|
-
var
|
|
1530
|
-
var PORT = Number(process2.env.OPENAPE_NEST_PORT ?? 9091);
|
|
1531
|
-
var APES_BIN = process2.env.OPENAPE_APES_BIN ?? "apes";
|
|
371
|
+
var APES_BIN = process3.env.OPENAPE_APES_BIN ?? "apes";
|
|
1532
372
|
function log(line) {
|
|
1533
|
-
|
|
373
|
+
process3.stderr.write(`${(/* @__PURE__ */ new Date()).toISOString()} ${line}
|
|
1534
374
|
`);
|
|
1535
375
|
}
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
return JSON.parse(text);
|
|
1544
|
-
} catch {
|
|
1545
|
-
throw new Error("invalid JSON body");
|
|
1546
|
-
}
|
|
1547
|
-
}
|
|
1548
|
-
function send(res, status, body) {
|
|
1549
|
-
res.writeHead(status, { "content-type": "application/json" });
|
|
1550
|
-
res.end(JSON.stringify(body));
|
|
1551
|
-
}
|
|
1552
|
-
function sendProblem(res, status, title) {
|
|
1553
|
-
send(res, status, { type: "about:blank", status, title });
|
|
1554
|
-
}
|
|
1555
|
-
async function requireNestGrant(req, res, expectedCommand) {
|
|
1556
|
-
const auth = req.headers.authorization;
|
|
1557
|
-
if (!auth || !auth.toLowerCase().startsWith("bearer ")) {
|
|
1558
|
-
sendProblem(res, 401, "Bearer grant token required");
|
|
1559
|
-
return null;
|
|
1560
|
-
}
|
|
1561
|
-
const token = auth.slice(7).trim();
|
|
1562
|
-
try {
|
|
1563
|
-
return await verifyNestGrant(token, expectedCommand);
|
|
1564
|
-
} catch (err) {
|
|
1565
|
-
if (err instanceof NestAuthError) {
|
|
1566
|
-
sendProblem(res, err.status, err.title);
|
|
1567
|
-
return null;
|
|
1568
|
-
}
|
|
1569
|
-
sendProblem(res, 401, err instanceof Error ? err.message : String(err));
|
|
1570
|
-
return null;
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
var server = createServer((req, res) => {
|
|
1574
|
-
;
|
|
1575
|
-
(async () => {
|
|
1576
|
-
try {
|
|
1577
|
-
const url = new URL(req.url ?? "/", `http://${HOST}:${PORT}`);
|
|
1578
|
-
const body = req.method && ["POST", "PUT", "PATCH"].includes(req.method) ? await readJsonBody(req) : {};
|
|
1579
|
-
if (req.method === "GET" && url.pathname === "/status") {
|
|
1580
|
-
const grant = await requireNestGrant(req, res, ["nest", "status"]);
|
|
1581
|
-
if (!grant) return;
|
|
1582
|
-
log(`nest: GET /status authorized (caller=${grant.caller}, grant=${grant.grantId})`);
|
|
1583
|
-
const ctx = { url, body, log, apesBin: APES_BIN, caller: grant.caller, grantId: grant.grantId };
|
|
1584
|
-
return send(res, 200, handleNestStatus(ctx));
|
|
1585
|
-
}
|
|
1586
|
-
if (req.method === "GET" && url.pathname === "/agents") {
|
|
1587
|
-
const grant = await requireNestGrant(req, res, ["nest", "list"]);
|
|
1588
|
-
if (!grant) return;
|
|
1589
|
-
log(`nest: GET /agents authorized (caller=${grant.caller}, grant=${grant.grantId})`);
|
|
1590
|
-
const ctx = { url, body, log, apesBin: APES_BIN, caller: grant.caller, grantId: grant.grantId };
|
|
1591
|
-
return send(res, 200, handleAgentsList(ctx));
|
|
1592
|
-
}
|
|
1593
|
-
if (req.method === "POST" && url.pathname === "/agents") {
|
|
1594
|
-
const name = body?.name;
|
|
1595
|
-
if (typeof name !== "string" || !name) {
|
|
1596
|
-
return sendProblem(res, 400, "POST /agents requires body.name (string)");
|
|
1597
|
-
}
|
|
1598
|
-
const grant = await requireNestGrant(req, res, ["nest", "spawn"]);
|
|
1599
|
-
if (!grant) return;
|
|
1600
|
-
log(`nest: POST /agents (spawn ${name}) authorized (caller=${grant.caller}, grant=${grant.grantId})`);
|
|
1601
|
-
const ctx = { url, body, log, apesBin: APES_BIN, caller: grant.caller, grantId: grant.grantId };
|
|
1602
|
-
const result = await handleAgentSpawn(ctx);
|
|
1603
|
-
return send(res, 201, result);
|
|
1604
|
-
}
|
|
1605
|
-
const destroyMatch = req.method === "DELETE" && url.pathname.match(/^\/agents\/([^/]+)$/);
|
|
1606
|
-
if (destroyMatch) {
|
|
1607
|
-
const name = destroyMatch[1];
|
|
1608
|
-
const grant = await requireNestGrant(req, res, ["nest", "destroy", name]);
|
|
1609
|
-
if (!grant) return;
|
|
1610
|
-
log(`nest: DELETE /agents/${name} authorized (caller=${grant.caller}, grant=${grant.grantId})`);
|
|
1611
|
-
const ctx = { url, body, log, apesBin: APES_BIN, caller: grant.caller, grantId: grant.grantId };
|
|
1612
|
-
const result = await handleAgentDestroy(ctx, name);
|
|
1613
|
-
return send(res, 200, result);
|
|
1614
|
-
}
|
|
1615
|
-
send(res, 404, { error: "not found" });
|
|
1616
|
-
} catch (err) {
|
|
1617
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1618
|
-
log(`nest: request failed: ${msg}`);
|
|
1619
|
-
send(res, 500, { error: msg });
|
|
1620
|
-
}
|
|
1621
|
-
})();
|
|
1622
|
-
});
|
|
1623
|
-
void primeJwksCache(log);
|
|
1624
|
-
server.listen(PORT, HOST, () => {
|
|
1625
|
-
log(`nest: listening on http://${HOST}:${PORT}`);
|
|
376
|
+
var supervisor = new Pm2Supervisor({ apesBin: APES_BIN, log });
|
|
377
|
+
var troopSync = new TroopSync({ apesBin: APES_BIN, log });
|
|
378
|
+
var intentChannel = new IntentChannel({ apesBin: APES_BIN, supervisor, log });
|
|
379
|
+
void supervisor.reconcile(listAgents()).then(
|
|
380
|
+
() => log("nest: pm2-supervisor reconciled with registry")
|
|
381
|
+
).catch((err) => {
|
|
382
|
+
log(`nest: pm2-supervisor reconcile failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1626
383
|
});
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
384
|
+
troopSync.start();
|
|
385
|
+
intentChannel.start();
|
|
386
|
+
var reaperTimer = setInterval(reapStaleResponses, 60 * 60 * 1e3, log);
|
|
387
|
+
process3.on("SIGTERM", () => {
|
|
388
|
+
log("nest: SIGTERM \u2014 stopping");
|
|
389
|
+
void supervisor.stopAll();
|
|
390
|
+
troopSync.stop();
|
|
391
|
+
intentChannel.stop();
|
|
392
|
+
clearInterval(reaperTimer);
|
|
393
|
+
process3.exit(0);
|
|
1630
394
|
});
|
|
1631
|
-
|
|
1632
|
-
log("nest: SIGINT \u2014
|
|
1633
|
-
|
|
395
|
+
process3.on("SIGINT", () => {
|
|
396
|
+
log("nest: SIGINT \u2014 stopping");
|
|
397
|
+
void supervisor.stopAll();
|
|
398
|
+
troopSync.stop();
|
|
399
|
+
intentChannel.stop();
|
|
400
|
+
clearInterval(reaperTimer);
|
|
401
|
+
process3.exit(0);
|
|
1634
402
|
});
|