@themoltnet/agent-daemon 0.45.0 → 0.46.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +289 -179
- package/dist/pi.d.ts.map +1 -1
- package/dist/pi.js +557 -2
- package/package.json +8 -6
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { defaultPiDaemonAdapter } from "./pi.js";
|
|
2
|
+
import { a as cryptoService, defaultPiDaemonAdapter, i as compileExecutionPlan, n as createExecutionPlanSnapshot, r as parseCredentialRequirements, t as runtimeExecutionOffer } from "./pi.js";
|
|
3
3
|
import { assertRuntimeAdapterSupportsProfile } from "./runtime.js";
|
|
4
4
|
import { Type } from "typebox";
|
|
5
5
|
import "multiformats/cid";
|
|
@@ -10,21 +10,11 @@ import { dirname, join, resolve } from "node:path";
|
|
|
10
10
|
import { parseArgs, promisify } from "node:util";
|
|
11
11
|
import { AgentRuntime, ApiTaskReporter, ApiTaskSource, PollingApiTaskSource, createLocalSeedSigner, resolveAgentIdentity, resolveProfileWarmSessionTtlSec, resolveRuntimeProfile, resolveRuntimeProfiles, validateRuntimeProfilePrerequisites } from "@themoltnet/agent-runtime";
|
|
12
12
|
import { GuestEnvironmentBoundaryError, assertGuestEnvironmentBoundary, createPiRetryTriage, findMainWorktree, isResolvedPathInsideRoot, normalizeRetryTriageResult, redactRetryTriageSecrets } from "@themoltnet/pi-runtime";
|
|
13
|
+
import { connect, createNodeSecretProviderRegistry } from "@themoltnet/sdk/node";
|
|
13
14
|
import { execFile, execFileSync } from "node:child_process";
|
|
14
15
|
import { createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, realpathSync, rmSync } from "node:fs";
|
|
15
|
-
import { AuthenticationError, MoltNetError,
|
|
16
|
-
import { createNodeSecretProviderRegistry } from "@themoltnet/sdk/node";
|
|
16
|
+
import { AuthenticationError, MoltNetError, createExecutorAttestor, readConfig, resolveEnvSecretReference, resolveIdentitySeed } from "@themoltnet/sdk";
|
|
17
17
|
import { createHash, randomUUID } from "node:crypto";
|
|
18
|
-
import * as ed from "@noble/ed25519";
|
|
19
|
-
import { createHash as createHash$1, randomBytes } from "crypto";
|
|
20
|
-
import "multiformats/codecs/raw";
|
|
21
|
-
import "multiformats/hashes/digest";
|
|
22
|
-
import "@noble/hashes/sha2";
|
|
23
|
-
import "multiformats/bases/base32";
|
|
24
|
-
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
25
|
-
import "@ipld/dag-cbor";
|
|
26
|
-
import "@noble/ciphers/chacha";
|
|
27
|
-
import "@noble/hashes/hkdf";
|
|
28
18
|
import { once } from "node:events";
|
|
29
19
|
import { pino, transport } from "pino";
|
|
30
20
|
import { metrics } from "@opentelemetry/api";
|
|
@@ -3710,6 +3700,9 @@ function loadConfig() {
|
|
|
3710
3700
|
signingPrivateKey: process.env["MOLTNET_PRIVATE_KEY"] ?? "",
|
|
3711
3701
|
signingPrivateKeyRef: process.env["MOLTNET_PRIVATE_KEY_REF"] ?? "",
|
|
3712
3702
|
gitAuthor: process.env["MOLTNET_GIT_AUTHOR"] ?? "",
|
|
3703
|
+
profileCredentialRequirements: process.env["MOLTNET_PROFILE_CREDENTIAL_REQUIREMENTS"] ?? "",
|
|
3704
|
+
credentialBindings: process.env["MOLTNET_CREDENTIAL_BINDINGS"] ?? "",
|
|
3705
|
+
credentialEnforcement: process.env["MOLTNET_CREDENTIAL_ENFORCEMENT"] ?? "",
|
|
3713
3706
|
traceIdlePolling: readBoolean("MOLTNET_TRACE_IDLE_POLLING", process.env["MOLTNET_TRACE_IDLE_POLLING"])
|
|
3714
3707
|
};
|
|
3715
3708
|
}
|
|
@@ -4288,172 +4281,6 @@ function recoverScratchWorkspacePath(producer, stateDirs) {
|
|
|
4288
4281
|
return existsSync(fallback) ? fallback : null;
|
|
4289
4282
|
}
|
|
4290
4283
|
//#endregion
|
|
4291
|
-
//#region ../../libs/crypto-service/src/ssh.ts
|
|
4292
|
-
/**
|
|
4293
|
-
* SSH key format conversion for MoltNet Ed25519 keys
|
|
4294
|
-
*
|
|
4295
|
-
* Converts MoltNet agent keys (ed25519:<base64>) to OpenSSH format
|
|
4296
|
-
* for use with git commit signing and SSH authentication.
|
|
4297
|
-
*/
|
|
4298
|
-
if (!ed.etc.sha512Sync) ed.etc.sha512Sync = (...m) => {
|
|
4299
|
-
const hash = createHash$1("sha512");
|
|
4300
|
-
m.forEach((msg) => hash.update(msg));
|
|
4301
|
-
return hash.digest();
|
|
4302
|
-
};
|
|
4303
|
-
new TextEncoder();
|
|
4304
|
-
//#endregion
|
|
4305
|
-
//#region ../../libs/crypto-service/src/crypto.service.ts
|
|
4306
|
-
/**
|
|
4307
|
-
* MoltNet Crypto Service
|
|
4308
|
-
*
|
|
4309
|
-
* Ed25519 cryptographic operations for agent identity
|
|
4310
|
-
* Uses @noble/ed25519 for pure TypeScript implementation
|
|
4311
|
-
*/
|
|
4312
|
-
ed.etc.sha512Sync = (...m) => {
|
|
4313
|
-
const hash = createHash$1("sha512");
|
|
4314
|
-
m.forEach((msg) => hash.update(msg));
|
|
4315
|
-
return hash.digest();
|
|
4316
|
-
};
|
|
4317
|
-
/** Domain-separation prefix for the signing payload envelope. */
|
|
4318
|
-
var DOMAIN_PREFIX = "moltnet:v1";
|
|
4319
|
-
/**
|
|
4320
|
-
* Build deterministic signing bytes with domain separation and
|
|
4321
|
-
* length-prefixed binary framing.
|
|
4322
|
-
*
|
|
4323
|
-
* Layout:
|
|
4324
|
-
* UTF-8("moltnet:v1") || u32be(len(msg_hash)) || msg_hash || u32be(len(nonce_bytes)) || nonce_bytes
|
|
4325
|
-
*
|
|
4326
|
-
* Where msg_hash = SHA-256(UTF-8(message)).
|
|
4327
|
-
*
|
|
4328
|
-
* This produces a fixed-structure byte sequence immune to whitespace,
|
|
4329
|
-
* newline, and encoding differences between runtimes.
|
|
4330
|
-
*/
|
|
4331
|
-
function buildSigningBytes(message, nonce) {
|
|
4332
|
-
const msgHash = createHash$1("sha256").update(Buffer.from(message, "utf-8")).digest();
|
|
4333
|
-
const nonceBytes = Buffer.from(nonce, "utf-8");
|
|
4334
|
-
const prefix = Buffer.from(DOMAIN_PREFIX, "utf-8");
|
|
4335
|
-
const buf = Buffer.alloc(prefix.length + 4 + msgHash.length + 4 + nonceBytes.length);
|
|
4336
|
-
let offset = 0;
|
|
4337
|
-
prefix.copy(buf, offset);
|
|
4338
|
-
offset += prefix.length;
|
|
4339
|
-
buf.writeUInt32BE(msgHash.length, offset);
|
|
4340
|
-
offset += 4;
|
|
4341
|
-
msgHash.copy(buf, offset);
|
|
4342
|
-
offset += msgHash.length;
|
|
4343
|
-
buf.writeUInt32BE(nonceBytes.length, offset);
|
|
4344
|
-
offset += 4;
|
|
4345
|
-
nonceBytes.copy(buf, offset);
|
|
4346
|
-
return new Uint8Array(buf);
|
|
4347
|
-
}
|
|
4348
|
-
var cryptoService = {
|
|
4349
|
-
async generateKeyPair() {
|
|
4350
|
-
const privateKeyBytes = ed.utils.randomPrivateKey();
|
|
4351
|
-
const publicKeyBytes = await ed.getPublicKeyAsync(privateKeyBytes);
|
|
4352
|
-
const privateKey = Buffer.from(privateKeyBytes).toString("base64");
|
|
4353
|
-
return {
|
|
4354
|
-
publicKey: `ed25519:${Buffer.from(publicKeyBytes).toString("base64")}`,
|
|
4355
|
-
privateKey,
|
|
4356
|
-
fingerprint: this.generateFingerprint(publicKeyBytes)
|
|
4357
|
-
};
|
|
4358
|
-
},
|
|
4359
|
-
generateFingerprint(publicKeyBytes) {
|
|
4360
|
-
return (createHash$1("sha256").update(publicKeyBytes).digest("hex").slice(0, 16).toUpperCase().match(/.{4}/g) ?? []).join("-");
|
|
4361
|
-
},
|
|
4362
|
-
parsePublicKey(publicKey) {
|
|
4363
|
-
const base64 = publicKey.replace(/^ed25519:/, "");
|
|
4364
|
-
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
4365
|
-
},
|
|
4366
|
-
async sign(message, privateKeyBase64) {
|
|
4367
|
-
const privateKeyBytes = new Uint8Array(Buffer.from(privateKeyBase64, "base64"));
|
|
4368
|
-
const messageBytes = new TextEncoder().encode(message);
|
|
4369
|
-
const signature = await ed.signAsync(messageBytes, privateKeyBytes);
|
|
4370
|
-
return Buffer.from(signature).toString("base64");
|
|
4371
|
-
},
|
|
4372
|
-
async verify(message, signature, publicKey) {
|
|
4373
|
-
try {
|
|
4374
|
-
const publicKeyBytes = this.parsePublicKey(publicKey);
|
|
4375
|
-
const signatureBytes = new Uint8Array(Buffer.from(signature, "base64"));
|
|
4376
|
-
const messageBytes = new TextEncoder().encode(message);
|
|
4377
|
-
return await ed.verifyAsync(signatureBytes, messageBytes, publicKeyBytes);
|
|
4378
|
-
} catch {
|
|
4379
|
-
return false;
|
|
4380
|
-
}
|
|
4381
|
-
},
|
|
4382
|
-
async signWithNonce(message, nonce, privateKeyBase64) {
|
|
4383
|
-
const privateKeyBytes = new Uint8Array(Buffer.from(privateKeyBase64, "base64"));
|
|
4384
|
-
const signingBytes = buildSigningBytes(message, nonce);
|
|
4385
|
-
const signature = await ed.signAsync(signingBytes, privateKeyBytes);
|
|
4386
|
-
return Buffer.from(signature).toString("base64");
|
|
4387
|
-
},
|
|
4388
|
-
async verifyWithNonce(message, nonce, signature, publicKey) {
|
|
4389
|
-
try {
|
|
4390
|
-
const publicKeyBytes = this.parsePublicKey(publicKey);
|
|
4391
|
-
const signatureBytes = new Uint8Array(Buffer.from(signature, "base64"));
|
|
4392
|
-
const signingBytes = buildSigningBytes(message, nonce);
|
|
4393
|
-
return await ed.verifyAsync(signatureBytes, signingBytes, publicKeyBytes);
|
|
4394
|
-
} catch {
|
|
4395
|
-
return false;
|
|
4396
|
-
}
|
|
4397
|
-
},
|
|
4398
|
-
async createSignedMessage(message, privateKeyBase64, publicKey) {
|
|
4399
|
-
return {
|
|
4400
|
-
message,
|
|
4401
|
-
signature: await this.sign(message, privateKeyBase64),
|
|
4402
|
-
publicKey
|
|
4403
|
-
};
|
|
4404
|
-
},
|
|
4405
|
-
async verifySignedMessage(signedMessage) {
|
|
4406
|
-
return this.verify(signedMessage.message, signedMessage.signature, signedMessage.publicKey);
|
|
4407
|
-
},
|
|
4408
|
-
generateChallenge() {
|
|
4409
|
-
return `moltnet:challenge:${randomBytes(32).toString("hex")}:${Date.now()}`;
|
|
4410
|
-
},
|
|
4411
|
-
async derivePublicKey(privateKeyBase64) {
|
|
4412
|
-
const privateKeyBytes = new Uint8Array(Buffer.from(privateKeyBase64, "base64"));
|
|
4413
|
-
const publicKeyBytes = await ed.getPublicKeyAsync(privateKeyBytes);
|
|
4414
|
-
return `ed25519:${Buffer.from(publicKeyBytes).toString("base64")}`;
|
|
4415
|
-
},
|
|
4416
|
-
getFingerprintFromPublicKey(publicKey) {
|
|
4417
|
-
const publicKeyBytes = this.parsePublicKey(publicKey);
|
|
4418
|
-
return this.generateFingerprint(publicKeyBytes);
|
|
4419
|
-
},
|
|
4420
|
-
deriveX25519PrivateKey(ed25519PrivateKeyBase64) {
|
|
4421
|
-
const seed = new Uint8Array(Buffer.from(ed25519PrivateKeyBase64, "base64"));
|
|
4422
|
-
const x25519Priv = ed25519.utils.toMontgomerySecret(seed);
|
|
4423
|
-
return Buffer.from(x25519Priv).toString("base64");
|
|
4424
|
-
},
|
|
4425
|
-
deriveX25519PublicKey(ed25519PublicKey) {
|
|
4426
|
-
const edPubBytes = this.parsePublicKey(ed25519PublicKey);
|
|
4427
|
-
const x25519Pub = ed25519.utils.toMontgomery(edPubBytes);
|
|
4428
|
-
return `x25519:${Buffer.from(x25519Pub).toString("base64")}`;
|
|
4429
|
-
},
|
|
4430
|
-
async createIdentityProof(identityId, privateKeyBase64) {
|
|
4431
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
4432
|
-
const message = `moltnet:register:${identityId}:${timestamp}`;
|
|
4433
|
-
return {
|
|
4434
|
-
message,
|
|
4435
|
-
signature: await this.sign(message, privateKeyBase64),
|
|
4436
|
-
timestamp
|
|
4437
|
-
};
|
|
4438
|
-
},
|
|
4439
|
-
async verifyIdentityProof(proof, publicKey, expectedIdentityId) {
|
|
4440
|
-
if (!await this.verify(proof.message, proof.signature, publicKey)) return false;
|
|
4441
|
-
const expectedPrefix = `moltnet:register:${expectedIdentityId}:`;
|
|
4442
|
-
if (!proof.message.startsWith(expectedPrefix)) return false;
|
|
4443
|
-
const proofTime = new Date(proof.timestamp).getTime();
|
|
4444
|
-
if (Date.now() - proofTime > 300 * 1e3) return false;
|
|
4445
|
-
return true;
|
|
4446
|
-
}
|
|
4447
|
-
};
|
|
4448
|
-
//#endregion
|
|
4449
|
-
//#region ../../libs/crypto-service/src/executor-attestation.ts
|
|
4450
|
-
ed.etc.sha512Sync = (...m) => {
|
|
4451
|
-
const hash = createHash("sha512");
|
|
4452
|
-
m.forEach((msg) => hash.update(msg));
|
|
4453
|
-
return hash.digest();
|
|
4454
|
-
};
|
|
4455
|
-
new TextEncoder().encode("SSHSIG");
|
|
4456
|
-
//#endregion
|
|
4457
4284
|
//#region src/lib/executor-attestation.ts
|
|
4458
4285
|
var DAEMON_REQUIRED_SCOPES = AGENT_CREDENTIAL_SCOPES;
|
|
4459
4286
|
async function resolveExecutorSigningPrivateKey(input) {
|
|
@@ -4859,6 +4686,257 @@ async function maybeWriteAnchors(output, ctx) {
|
|
|
4859
4686
|
}
|
|
4860
4687
|
}
|
|
4861
4688
|
//#endregion
|
|
4689
|
+
//#region ../../libs/execution-integrations/src/credential-broker.ts
|
|
4690
|
+
async function checkCredentialReadiness(requirements, bindings, providers) {
|
|
4691
|
+
const records = [];
|
|
4692
|
+
for (const requirement of requirements) {
|
|
4693
|
+
const binding = ownBinding(bindings, requirement.name);
|
|
4694
|
+
if (binding === void 0) {
|
|
4695
|
+
records.push({
|
|
4696
|
+
name: requirement.name,
|
|
4697
|
+
required: requirement.required,
|
|
4698
|
+
status: requirement.required ? "required_binding_missing" : "binding_absent"
|
|
4699
|
+
});
|
|
4700
|
+
continue;
|
|
4701
|
+
}
|
|
4702
|
+
const bindingDigest = await digestBindingReference(binding.reference);
|
|
4703
|
+
const source = binding.source ?? "local-activation";
|
|
4704
|
+
if (providers.get(binding.reference.provider) === void 0) {
|
|
4705
|
+
records.push({
|
|
4706
|
+
name: requirement.name,
|
|
4707
|
+
required: requirement.required,
|
|
4708
|
+
status: "provider_unavailable",
|
|
4709
|
+
bindingDigest,
|
|
4710
|
+
source
|
|
4711
|
+
});
|
|
4712
|
+
continue;
|
|
4713
|
+
}
|
|
4714
|
+
const probe = await providers.probe(binding.reference);
|
|
4715
|
+
records.push({
|
|
4716
|
+
name: requirement.name,
|
|
4717
|
+
required: requirement.required,
|
|
4718
|
+
status: probe === "present" ? "ready" : probe === "absent" ? "binding_absent" : "host_store_inaccessible",
|
|
4719
|
+
bindingDigest,
|
|
4720
|
+
source
|
|
4721
|
+
});
|
|
4722
|
+
}
|
|
4723
|
+
return records;
|
|
4724
|
+
}
|
|
4725
|
+
async function digestBindingReference(reference) {
|
|
4726
|
+
const bytes = new TextEncoder().encode(`${reference.provider}\u0000${reference.key}`);
|
|
4727
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
|
|
4728
|
+
return `sha256:${[...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 16)}`;
|
|
4729
|
+
}
|
|
4730
|
+
function ownBinding(bindings, name) {
|
|
4731
|
+
return Object.hasOwn(bindings, name) ? bindings[name] : void 0;
|
|
4732
|
+
}
|
|
4733
|
+
//#endregion
|
|
4734
|
+
//#region ../../libs/execution-integrations/src/runtime-profile.ts
|
|
4735
|
+
var CURRENT_EFFECTIVE_POLICY_SNAPSHOT_VERSION = "effective-policy:v1";
|
|
4736
|
+
/**
|
|
4737
|
+
* Maps resolved product authority into portable intent. Policy composition is
|
|
4738
|
+
* deliberately upstream: this boundary accepts no policy IDs and performs no
|
|
4739
|
+
* union, lookup, or precedence handling.
|
|
4740
|
+
*/
|
|
4741
|
+
function executionIntentFromRuntimeProfile(input) {
|
|
4742
|
+
if (input.policy.snapshot.runtimeKind !== input.profile.runtimeKind) throw new Error("resolved policy authority does not match runtime profile");
|
|
4743
|
+
const network = input.profile.sandboxConfig.network;
|
|
4744
|
+
return {
|
|
4745
|
+
mode: input.mode,
|
|
4746
|
+
profile: {
|
|
4747
|
+
id: input.profile.id,
|
|
4748
|
+
revision: input.profileRevision,
|
|
4749
|
+
definitionCid: input.profile.definitionCid
|
|
4750
|
+
},
|
|
4751
|
+
authority: {
|
|
4752
|
+
policySnapshotHash: input.policy.hash,
|
|
4753
|
+
policySnapshotVersion: input.policy.snapshot.version,
|
|
4754
|
+
...input.policy.authorizedControls !== void 0 && { authorizedControls: [...input.policy.authorizedControls] }
|
|
4755
|
+
},
|
|
4756
|
+
credentialRequirements: structuredClone(input.credentialRequirements),
|
|
4757
|
+
requiredCapabilities: [...input.requiredCapabilities ?? []],
|
|
4758
|
+
lease: {
|
|
4759
|
+
ttlSec: input.profile.leaseTtlSec,
|
|
4760
|
+
requiredControls: [...input.requiredLeaseControls ?? []]
|
|
4761
|
+
},
|
|
4762
|
+
network: {
|
|
4763
|
+
allowedHosts: [...network?.allowedHosts ?? []],
|
|
4764
|
+
allowedInternalHosts: [...network?.allowedInternalHosts ?? []]
|
|
4765
|
+
},
|
|
4766
|
+
provenance: {
|
|
4767
|
+
profile: input.profile.source,
|
|
4768
|
+
policy: `runtime-policy-snapshot:${input.policy.hash}`,
|
|
4769
|
+
requirements: input.requirementsProvenance
|
|
4770
|
+
}
|
|
4771
|
+
};
|
|
4772
|
+
}
|
|
4773
|
+
//#endregion
|
|
4774
|
+
//#region src/lib/governance-plan.ts
|
|
4775
|
+
/**
|
|
4776
|
+
* Observe-only governance-plan compilation (#1970 private slice).
|
|
4777
|
+
*
|
|
4778
|
+
* Distinct from `task-execution-plan.ts` (workspace/session planning): this
|
|
4779
|
+
* module compiles the CREDENTIAL/CAPABILITY governance plan from trusted
|
|
4780
|
+
* local configuration and logs its value-free decisions. It gates nothing
|
|
4781
|
+
* yet — enforcement is a separate, later change.
|
|
4782
|
+
*/
|
|
4783
|
+
var DEFAULT_GOVERNANCE_OBSERVE_TIMEOUT_MS = 2e3;
|
|
4784
|
+
/**
|
|
4785
|
+
* Two distinct provenance sources (#2022 review): requirements come from a
|
|
4786
|
+
* profile-side/private input (`MOLTNET_PROFILE_CREDENTIAL_REQUIREMENTS`, a
|
|
4787
|
+
* JSON map of profile id → requirements) and bindings from trusted
|
|
4788
|
+
* local/deployment configuration (`MOLTNET_CREDENTIAL_BINDINGS`). Both raw
|
|
4789
|
+
* values are read once in config.ts. Both empty → null (observer disabled).
|
|
4790
|
+
* Malformed configuration throws — a truncated credential policy must never
|
|
4791
|
+
* be silently ignored.
|
|
4792
|
+
*/
|
|
4793
|
+
function loadRuntimeCredentialConfig(raw) {
|
|
4794
|
+
const hasRequirements = raw.profileRequirements.trim() !== "";
|
|
4795
|
+
const hasBindings = raw.bindings.trim() !== "";
|
|
4796
|
+
if (!hasRequirements && !hasBindings) return null;
|
|
4797
|
+
const requirementsByProfile = {};
|
|
4798
|
+
if (hasRequirements) {
|
|
4799
|
+
const parsed = JSON.parse(raw.profileRequirements);
|
|
4800
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("MOLTNET_PROFILE_CREDENTIAL_REQUIREMENTS must be a JSON object keyed by profile id");
|
|
4801
|
+
for (const [profileId, value] of Object.entries(parsed)) requirementsByProfile[profileId] = parseCredentialRequirements(value);
|
|
4802
|
+
}
|
|
4803
|
+
const bindings = {};
|
|
4804
|
+
if (hasBindings) {
|
|
4805
|
+
const parsed = JSON.parse(raw.bindings);
|
|
4806
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("MOLTNET_CREDENTIAL_BINDINGS must be a JSON object");
|
|
4807
|
+
for (const [name, binding] of Object.entries(parsed)) {
|
|
4808
|
+
if (typeof binding?.reference?.provider !== "string" || typeof binding.reference.key !== "string") throw new Error(`MOLTNET_CREDENTIAL_BINDINGS binding "${name}" must carry a { reference: { provider, key } }`);
|
|
4809
|
+
bindings[name] = {
|
|
4810
|
+
...binding,
|
|
4811
|
+
source: "local-bindings-config"
|
|
4812
|
+
};
|
|
4813
|
+
}
|
|
4814
|
+
}
|
|
4815
|
+
return {
|
|
4816
|
+
requirementsByProfile,
|
|
4817
|
+
bindings,
|
|
4818
|
+
sources: {
|
|
4819
|
+
requirements: "profile-requirements-config",
|
|
4820
|
+
bindings: "local-bindings-config"
|
|
4821
|
+
}
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
/**
|
|
4825
|
+
* Resolve the credential-governance enforcement mode, mirroring the runtime
|
|
4826
|
+
* tool-policy `off | watch | enforce` ladder. Unset defaults to `watch` when
|
|
4827
|
+
* requirement/binding sources are configured, `off` otherwise. `enforce` is
|
|
4828
|
+
* rejected until the enforcement flip (skip-before-claim) is implemented —
|
|
4829
|
+
* accepting it as a silent watch would misrepresent the deployment.
|
|
4830
|
+
*/
|
|
4831
|
+
function resolveCredentialEnforcement(raw, sources) {
|
|
4832
|
+
const configured = sources.profileRequirements.trim() !== "" || sources.bindings.trim() !== "";
|
|
4833
|
+
const value = raw.trim();
|
|
4834
|
+
if (value === "") return configured ? "watch" : "off";
|
|
4835
|
+
if (value === "off" || value === "watch") return value;
|
|
4836
|
+
if (value === "enforce") throw new Error("MOLTNET_CREDENTIAL_ENFORCEMENT=enforce is not implemented yet: the skip-before-claim flip is a separate change. Use watch (audit only).");
|
|
4837
|
+
throw new Error(`MOLTNET_CREDENTIAL_ENFORCEMENT must be off, watch or enforce; got "${value}"`);
|
|
4838
|
+
}
|
|
4839
|
+
async function observeGovernancePlan(input) {
|
|
4840
|
+
const unavailableReason = authorityUnavailableReason(input);
|
|
4841
|
+
if (unavailableReason !== null) {
|
|
4842
|
+
(input.logger.warn ?? input.logger.info).call(input.logger, {
|
|
4843
|
+
mode: "observe",
|
|
4844
|
+
taskId: input.taskId,
|
|
4845
|
+
attemptN: input.attemptN,
|
|
4846
|
+
profileId: input.profile.id,
|
|
4847
|
+
reason: unavailableReason
|
|
4848
|
+
}, "agent-daemon.governance_plan_unavailable");
|
|
4849
|
+
return {
|
|
4850
|
+
status: "unavailable",
|
|
4851
|
+
snapshot: null,
|
|
4852
|
+
reason: unavailableReason
|
|
4853
|
+
};
|
|
4854
|
+
}
|
|
4855
|
+
const { runtimeProfileRevision, policySnapshotHash } = input.claimAuthority;
|
|
4856
|
+
if (runtimeProfileRevision === void 0 || policySnapshotHash === void 0) throw new Error("validated claim authority is missing immutable pins");
|
|
4857
|
+
if (input.offer === void 0) throw new Error("validated execution offer is missing");
|
|
4858
|
+
const requirements = input.config.requirementsByProfile[input.profile.id] ?? [];
|
|
4859
|
+
const credentialReadiness = await checkCredentialReadiness(requirements, input.config.bindings, input.registry);
|
|
4860
|
+
const intent = executionIntentFromRuntimeProfile({
|
|
4861
|
+
mode: "watch",
|
|
4862
|
+
profile: input.profile,
|
|
4863
|
+
profileRevision: runtimeProfileRevision,
|
|
4864
|
+
policy: {
|
|
4865
|
+
hash: policySnapshotHash,
|
|
4866
|
+
snapshot: {
|
|
4867
|
+
version: CURRENT_EFFECTIVE_POLICY_SNAPSHOT_VERSION,
|
|
4868
|
+
runtimeKind: input.profile.runtimeKind
|
|
4869
|
+
},
|
|
4870
|
+
authorizedControls: void 0
|
|
4871
|
+
},
|
|
4872
|
+
credentialRequirements: requirements,
|
|
4873
|
+
requiredCapabilities: [],
|
|
4874
|
+
requirementsProvenance: input.config.sources.requirements
|
|
4875
|
+
});
|
|
4876
|
+
const plan = compileExecutionPlan({
|
|
4877
|
+
intent,
|
|
4878
|
+
offer: input.offer,
|
|
4879
|
+
credentialReadiness
|
|
4880
|
+
});
|
|
4881
|
+
const snapshot = await createExecutionPlanSnapshot({
|
|
4882
|
+
intent,
|
|
4883
|
+
offer: input.offer,
|
|
4884
|
+
credentialReadiness,
|
|
4885
|
+
plan
|
|
4886
|
+
});
|
|
4887
|
+
const logObject = {
|
|
4888
|
+
mode: "observe",
|
|
4889
|
+
taskId: input.taskId,
|
|
4890
|
+
attemptN: input.attemptN,
|
|
4891
|
+
profileId: input.profile.id,
|
|
4892
|
+
sources: input.config.sources,
|
|
4893
|
+
snapshotCid: snapshot.cid,
|
|
4894
|
+
profileRevision: snapshot.intent.profile.revision,
|
|
4895
|
+
policySnapshotHash: snapshot.intent.authority.policySnapshotHash,
|
|
4896
|
+
launchable: plan.launchable,
|
|
4897
|
+
decisions: plan.decisions,
|
|
4898
|
+
credentialReadiness
|
|
4899
|
+
};
|
|
4900
|
+
if (plan.launchable) input.logger.info(logObject, "agent-daemon.governance_plan");
|
|
4901
|
+
else (input.logger.warn ?? input.logger.info).call(input.logger, logObject, "agent-daemon.governance_plan_would_block");
|
|
4902
|
+
return {
|
|
4903
|
+
status: "observed",
|
|
4904
|
+
snapshot
|
|
4905
|
+
};
|
|
4906
|
+
}
|
|
4907
|
+
/**
|
|
4908
|
+
* Observe without allowing a stuck keyring/provider to delay task execution.
|
|
4909
|
+
* The observer is intentionally non-gating: failures and deadlines are logged
|
|
4910
|
+
* with claim correlation and converted to `null`.
|
|
4911
|
+
*/
|
|
4912
|
+
async function observeGovernancePlanSafely(input, timeoutMs = DEFAULT_GOVERNANCE_OBSERVE_TIMEOUT_MS) {
|
|
4913
|
+
let timeout;
|
|
4914
|
+
try {
|
|
4915
|
+
return await Promise.race([observeGovernancePlan(input), new Promise((_resolve, reject) => {
|
|
4916
|
+
timeout = setTimeout(() => reject(/* @__PURE__ */ new Error("governance observation timed out")), timeoutMs);
|
|
4917
|
+
})]);
|
|
4918
|
+
} catch (error) {
|
|
4919
|
+
(input.logger.warn ?? input.logger.info).call(input.logger, {
|
|
4920
|
+
mode: "observe",
|
|
4921
|
+
taskId: input.taskId,
|
|
4922
|
+
attemptN: input.attemptN,
|
|
4923
|
+
err: error instanceof Error ? error.message : String(error)
|
|
4924
|
+
}, "agent-daemon.governance_plan_observe_failed");
|
|
4925
|
+
return null;
|
|
4926
|
+
} finally {
|
|
4927
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
function authorityUnavailableReason(input) {
|
|
4931
|
+
const authority = input.claimAuthority;
|
|
4932
|
+
if (authority.runtimeProfileId === void 0 || authority.runtimeProfileRevision === void 0 || authority.policySnapshotHash === void 0 || authority.executorFingerprint === void 0) return "claim_authority_unpinned";
|
|
4933
|
+
if (authority.runtimeProfileId !== input.profile.id) return "runtime_profile_mismatch";
|
|
4934
|
+
if (authority.executorFingerprint !== input.executorFingerprint) return "executor_fingerprint_mismatch";
|
|
4935
|
+
if (input.offer === void 0) return "execution_offer_unavailable";
|
|
4936
|
+
if (input.offer.executor.fingerprint !== input.executorFingerprint) return "executor_fingerprint_mismatch";
|
|
4937
|
+
return null;
|
|
4938
|
+
}
|
|
4939
|
+
//#endregion
|
|
4862
4940
|
//#region src/lib/logger.ts
|
|
4863
4941
|
/**
|
|
4864
4942
|
* Logger setup + teardown for the agent-daemon CLI commands.
|
|
@@ -5696,6 +5774,11 @@ async function runPolling(opts) {
|
|
|
5696
5774
|
}
|
|
5697
5775
|
if (taskTypes.length === 0) console.error(`[${opts.modeLabel}] --task-types is empty — daemon will accept any registered type. Pass an explicit list to limit scope (e.g. --task-types fulfill_brief).`);
|
|
5698
5776
|
const cfg = loadConfig();
|
|
5777
|
+
const credentialSources = {
|
|
5778
|
+
profileRequirements: cfg.profileCredentialRequirements,
|
|
5779
|
+
bindings: cfg.credentialBindings
|
|
5780
|
+
};
|
|
5781
|
+
const runtimeCredentialConfig = resolveCredentialEnforcement(cfg.credentialEnforcement, credentialSources) === "off" ? null : loadRuntimeCredentialConfig(credentialSources);
|
|
5699
5782
|
const agentRootDir = resolve(process.cwd(), values["agent-root"] ?? process.cwd());
|
|
5700
5783
|
const { ctx, signingPrivateKey, startupWhoami, agentIdentity, hostCapabilitySigner } = await (async () => {
|
|
5701
5784
|
let gate = "resolve_agent_context";
|
|
@@ -6062,6 +6145,17 @@ async function runPolling(opts) {
|
|
|
6062
6145
|
executeTask: async (claimedTask, reporter) => {
|
|
6063
6146
|
const selected = runtimeForClaimedTask(runtimes, claimedTask);
|
|
6064
6147
|
const { common, executionPlans, profile, sandbox, slotIdentity, stateDirs } = selected;
|
|
6148
|
+
if (runtimeCredentialConfig) await observeGovernancePlanSafely({
|
|
6149
|
+
config: runtimeCredentialConfig,
|
|
6150
|
+
profile,
|
|
6151
|
+
offer: runtimeExecutionOffer(selected.preparedRuntime, selected.preparedRuntime.attestor.fingerprint),
|
|
6152
|
+
registry: createNodeSecretProviderRegistry(),
|
|
6153
|
+
executorFingerprint: selected.preparedRuntime.attestor.fingerprint,
|
|
6154
|
+
claimAuthority: claimedTask.claimAuthority ?? {},
|
|
6155
|
+
taskId: claimedTask.task.id,
|
|
6156
|
+
attemptN: claimedTask.attemptN,
|
|
6157
|
+
logger: rootLogger
|
|
6158
|
+
});
|
|
6065
6159
|
const taskLogger = rootLogger.child({
|
|
6066
6160
|
runtimeProfileId: profile.id,
|
|
6067
6161
|
runtimeProfileName: profile.name,
|
|
@@ -6332,6 +6426,11 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
|
|
|
6332
6426
|
return 1;
|
|
6333
6427
|
}
|
|
6334
6428
|
const cfg = loadConfig();
|
|
6429
|
+
const credentialSources = {
|
|
6430
|
+
profileRequirements: cfg.profileCredentialRequirements,
|
|
6431
|
+
bindings: cfg.credentialBindings
|
|
6432
|
+
};
|
|
6433
|
+
const runtimeCredentialConfig = resolveCredentialEnforcement(cfg.credentialEnforcement, credentialSources) === "off" ? null : loadRuntimeCredentialConfig(credentialSources);
|
|
6335
6434
|
const initialOpts = opts;
|
|
6336
6435
|
const agentRootDir = resolve(process.cwd(), values["agent-root"] ?? process.cwd());
|
|
6337
6436
|
const { ctx, signingPrivateKey, agentIdentity, hostCapabilitySigner } = await (async () => {
|
|
@@ -6581,6 +6680,17 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
|
|
|
6581
6680
|
maxBashTimeouts: opts.maxBashTimeouts
|
|
6582
6681
|
});
|
|
6583
6682
|
const executeTask = async (claimedTask, reporter) => {
|
|
6683
|
+
if (runtimeCredentialConfig) await observeGovernancePlanSafely({
|
|
6684
|
+
config: runtimeCredentialConfig,
|
|
6685
|
+
profile,
|
|
6686
|
+
offer: runtimeExecutionOffer(preparedRuntime, preparedRuntime.attestor.fingerprint),
|
|
6687
|
+
registry: createNodeSecretProviderRegistry(),
|
|
6688
|
+
executorFingerprint: preparedRuntime.attestor.fingerprint,
|
|
6689
|
+
claimAuthority: claimedTask.claimAuthority ?? {},
|
|
6690
|
+
taskId: claimedTask.task.id,
|
|
6691
|
+
attemptN: claimedTask.attemptN,
|
|
6692
|
+
logger: rootLogger
|
|
6693
|
+
});
|
|
6584
6694
|
let executionPlan;
|
|
6585
6695
|
try {
|
|
6586
6696
|
executionPlan = await executionPlans.getOrCreate(claimedTask);
|
package/dist/pi.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../src/pi.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../src/pi.ts"],"names":[],"mappings":"AACA,OAAO,EASL,KAAK,mBAAmB,EACzB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,oBAAoB,EAAyB,MAAM,cAAc,CAAC;AAEhF,eAAO,MAAM,oBAAoB,kkBAIvB,CAAC;AAEX,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,mBAAmB,GAC3B,oBAAoB,CAkEtB;AAED,eAAO,MAAM,0BAA0B,qBASrC,CAAC;AAEH,eAAO,MAAM,sBAAsB,sBAElC,CAAC"}
|
package/dist/pi.js
CHANGED
|
@@ -1,5 +1,558 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { Type } from "typebox";
|
|
3
|
+
import { CID } from "multiformats/cid";
|
|
4
|
+
import * as json from "multiformats/codecs/json";
|
|
5
|
+
import { sha256 } from "multiformats/hashes/sha2";
|
|
6
|
+
import { Value } from "typebox/value";
|
|
2
7
|
import { GONDOLIN_BASE_EXECUTABLES, GONDOLIN_TOOL_NAMES, MOLTNET_TOOL_NAMES, agentSigningCapability, buildPiExecutorManifest, createPiTaskExecutor, defineGondolinTemplate, definePiRuntime } from "@themoltnet/pi-runtime";
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import * as ed from "@noble/ed25519";
|
|
10
|
+
import { createHash as createHash$1, randomBytes } from "crypto";
|
|
11
|
+
import "multiformats/codecs/raw";
|
|
12
|
+
import "multiformats/hashes/digest";
|
|
13
|
+
import "@noble/hashes/sha2";
|
|
14
|
+
import "multiformats/bases/base32";
|
|
15
|
+
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
16
|
+
import "@ipld/dag-cbor";
|
|
17
|
+
import "@noble/ciphers/chacha";
|
|
18
|
+
import "@noble/hashes/hkdf";
|
|
19
|
+
//#region ../../libs/crypto-service/src/ssh.ts
|
|
20
|
+
/**
|
|
21
|
+
* SSH key format conversion for MoltNet Ed25519 keys
|
|
22
|
+
*
|
|
23
|
+
* Converts MoltNet agent keys (ed25519:<base64>) to OpenSSH format
|
|
24
|
+
* for use with git commit signing and SSH authentication.
|
|
25
|
+
*/
|
|
26
|
+
if (!ed.etc.sha512Sync) ed.etc.sha512Sync = (...m) => {
|
|
27
|
+
const hash = createHash$1("sha512");
|
|
28
|
+
m.forEach((msg) => hash.update(msg));
|
|
29
|
+
return hash.digest();
|
|
30
|
+
};
|
|
31
|
+
new TextEncoder();
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region ../../libs/crypto-service/src/crypto.service.ts
|
|
34
|
+
/**
|
|
35
|
+
* MoltNet Crypto Service
|
|
36
|
+
*
|
|
37
|
+
* Ed25519 cryptographic operations for agent identity
|
|
38
|
+
* Uses @noble/ed25519 for pure TypeScript implementation
|
|
39
|
+
*/
|
|
40
|
+
ed.etc.sha512Sync = (...m) => {
|
|
41
|
+
const hash = createHash$1("sha512");
|
|
42
|
+
m.forEach((msg) => hash.update(msg));
|
|
43
|
+
return hash.digest();
|
|
44
|
+
};
|
|
45
|
+
/** Domain-separation prefix for the signing payload envelope. */
|
|
46
|
+
var DOMAIN_PREFIX = "moltnet:v1";
|
|
47
|
+
/**
|
|
48
|
+
* Build deterministic signing bytes with domain separation and
|
|
49
|
+
* length-prefixed binary framing.
|
|
50
|
+
*
|
|
51
|
+
* Layout:
|
|
52
|
+
* UTF-8("moltnet:v1") || u32be(len(msg_hash)) || msg_hash || u32be(len(nonce_bytes)) || nonce_bytes
|
|
53
|
+
*
|
|
54
|
+
* Where msg_hash = SHA-256(UTF-8(message)).
|
|
55
|
+
*
|
|
56
|
+
* This produces a fixed-structure byte sequence immune to whitespace,
|
|
57
|
+
* newline, and encoding differences between runtimes.
|
|
58
|
+
*/
|
|
59
|
+
function buildSigningBytes(message, nonce) {
|
|
60
|
+
const msgHash = createHash$1("sha256").update(Buffer.from(message, "utf-8")).digest();
|
|
61
|
+
const nonceBytes = Buffer.from(nonce, "utf-8");
|
|
62
|
+
const prefix = Buffer.from(DOMAIN_PREFIX, "utf-8");
|
|
63
|
+
const buf = Buffer.alloc(prefix.length + 4 + msgHash.length + 4 + nonceBytes.length);
|
|
64
|
+
let offset = 0;
|
|
65
|
+
prefix.copy(buf, offset);
|
|
66
|
+
offset += prefix.length;
|
|
67
|
+
buf.writeUInt32BE(msgHash.length, offset);
|
|
68
|
+
offset += 4;
|
|
69
|
+
msgHash.copy(buf, offset);
|
|
70
|
+
offset += msgHash.length;
|
|
71
|
+
buf.writeUInt32BE(nonceBytes.length, offset);
|
|
72
|
+
offset += 4;
|
|
73
|
+
nonceBytes.copy(buf, offset);
|
|
74
|
+
return new Uint8Array(buf);
|
|
75
|
+
}
|
|
76
|
+
var cryptoService = {
|
|
77
|
+
async generateKeyPair() {
|
|
78
|
+
const privateKeyBytes = ed.utils.randomPrivateKey();
|
|
79
|
+
const publicKeyBytes = await ed.getPublicKeyAsync(privateKeyBytes);
|
|
80
|
+
const privateKey = Buffer.from(privateKeyBytes).toString("base64");
|
|
81
|
+
return {
|
|
82
|
+
publicKey: `ed25519:${Buffer.from(publicKeyBytes).toString("base64")}`,
|
|
83
|
+
privateKey,
|
|
84
|
+
fingerprint: this.generateFingerprint(publicKeyBytes)
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
generateFingerprint(publicKeyBytes) {
|
|
88
|
+
return (createHash$1("sha256").update(publicKeyBytes).digest("hex").slice(0, 16).toUpperCase().match(/.{4}/g) ?? []).join("-");
|
|
89
|
+
},
|
|
90
|
+
parsePublicKey(publicKey) {
|
|
91
|
+
const base64 = publicKey.replace(/^ed25519:/, "");
|
|
92
|
+
return new Uint8Array(Buffer.from(base64, "base64"));
|
|
93
|
+
},
|
|
94
|
+
async sign(message, privateKeyBase64) {
|
|
95
|
+
const privateKeyBytes = new Uint8Array(Buffer.from(privateKeyBase64, "base64"));
|
|
96
|
+
const messageBytes = new TextEncoder().encode(message);
|
|
97
|
+
const signature = await ed.signAsync(messageBytes, privateKeyBytes);
|
|
98
|
+
return Buffer.from(signature).toString("base64");
|
|
99
|
+
},
|
|
100
|
+
async verify(message, signature, publicKey) {
|
|
101
|
+
try {
|
|
102
|
+
const publicKeyBytes = this.parsePublicKey(publicKey);
|
|
103
|
+
const signatureBytes = new Uint8Array(Buffer.from(signature, "base64"));
|
|
104
|
+
const messageBytes = new TextEncoder().encode(message);
|
|
105
|
+
return await ed.verifyAsync(signatureBytes, messageBytes, publicKeyBytes);
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
async signWithNonce(message, nonce, privateKeyBase64) {
|
|
111
|
+
const privateKeyBytes = new Uint8Array(Buffer.from(privateKeyBase64, "base64"));
|
|
112
|
+
const signingBytes = buildSigningBytes(message, nonce);
|
|
113
|
+
const signature = await ed.signAsync(signingBytes, privateKeyBytes);
|
|
114
|
+
return Buffer.from(signature).toString("base64");
|
|
115
|
+
},
|
|
116
|
+
async verifyWithNonce(message, nonce, signature, publicKey) {
|
|
117
|
+
try {
|
|
118
|
+
const publicKeyBytes = this.parsePublicKey(publicKey);
|
|
119
|
+
const signatureBytes = new Uint8Array(Buffer.from(signature, "base64"));
|
|
120
|
+
const signingBytes = buildSigningBytes(message, nonce);
|
|
121
|
+
return await ed.verifyAsync(signatureBytes, signingBytes, publicKeyBytes);
|
|
122
|
+
} catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
async createSignedMessage(message, privateKeyBase64, publicKey) {
|
|
127
|
+
return {
|
|
128
|
+
message,
|
|
129
|
+
signature: await this.sign(message, privateKeyBase64),
|
|
130
|
+
publicKey
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
async verifySignedMessage(signedMessage) {
|
|
134
|
+
return this.verify(signedMessage.message, signedMessage.signature, signedMessage.publicKey);
|
|
135
|
+
},
|
|
136
|
+
generateChallenge() {
|
|
137
|
+
return `moltnet:challenge:${randomBytes(32).toString("hex")}:${Date.now()}`;
|
|
138
|
+
},
|
|
139
|
+
async derivePublicKey(privateKeyBase64) {
|
|
140
|
+
const privateKeyBytes = new Uint8Array(Buffer.from(privateKeyBase64, "base64"));
|
|
141
|
+
const publicKeyBytes = await ed.getPublicKeyAsync(privateKeyBytes);
|
|
142
|
+
return `ed25519:${Buffer.from(publicKeyBytes).toString("base64")}`;
|
|
143
|
+
},
|
|
144
|
+
getFingerprintFromPublicKey(publicKey) {
|
|
145
|
+
const publicKeyBytes = this.parsePublicKey(publicKey);
|
|
146
|
+
return this.generateFingerprint(publicKeyBytes);
|
|
147
|
+
},
|
|
148
|
+
deriveX25519PrivateKey(ed25519PrivateKeyBase64) {
|
|
149
|
+
const seed = new Uint8Array(Buffer.from(ed25519PrivateKeyBase64, "base64"));
|
|
150
|
+
const x25519Priv = ed25519.utils.toMontgomerySecret(seed);
|
|
151
|
+
return Buffer.from(x25519Priv).toString("base64");
|
|
152
|
+
},
|
|
153
|
+
deriveX25519PublicKey(ed25519PublicKey) {
|
|
154
|
+
const edPubBytes = this.parsePublicKey(ed25519PublicKey);
|
|
155
|
+
const x25519Pub = ed25519.utils.toMontgomery(edPubBytes);
|
|
156
|
+
return `x25519:${Buffer.from(x25519Pub).toString("base64")}`;
|
|
157
|
+
},
|
|
158
|
+
async createIdentityProof(identityId, privateKeyBase64) {
|
|
159
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
160
|
+
const message = `moltnet:register:${identityId}:${timestamp}`;
|
|
161
|
+
return {
|
|
162
|
+
message,
|
|
163
|
+
signature: await this.sign(message, privateKeyBase64),
|
|
164
|
+
timestamp
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
async verifyIdentityProof(proof, publicKey, expectedIdentityId) {
|
|
168
|
+
if (!await this.verify(proof.message, proof.signature, publicKey)) return false;
|
|
169
|
+
const expectedPrefix = `moltnet:register:${expectedIdentityId}:`;
|
|
170
|
+
if (!proof.message.startsWith(expectedPrefix)) return false;
|
|
171
|
+
const proofTime = new Date(proof.timestamp).getTime();
|
|
172
|
+
if (Date.now() - proofTime > 300 * 1e3) return false;
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region ../../libs/crypto-service/src/executor-attestation.ts
|
|
178
|
+
ed.etc.sha512Sync = (...m) => {
|
|
179
|
+
const hash = createHash("sha512");
|
|
180
|
+
m.forEach((msg) => hash.update(msg));
|
|
181
|
+
return hash.digest();
|
|
182
|
+
};
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region ../../libs/crypto-service/src/json-cid.ts
|
|
185
|
+
/**
|
|
186
|
+
* Generic JSON CID — CIDv1 for arbitrary JSON-serialisable values.
|
|
187
|
+
*
|
|
188
|
+
* Uses the dag-json codec and sha2-256, producing a base32lower CIDv1.
|
|
189
|
+
* Suitable for content-addressing task inputs, schema objects, and other
|
|
190
|
+
* JSON payloads that don't need diary-entry canonical normalisation.
|
|
191
|
+
*/
|
|
192
|
+
async function computeJsonCid(value) {
|
|
193
|
+
const bytes = json.encode(value);
|
|
194
|
+
const hash = await sha256.digest(bytes);
|
|
195
|
+
return CID.create(1, json.code, hash).toString();
|
|
196
|
+
}
|
|
197
|
+
new TextEncoder().encode("SSHSIG");
|
|
198
|
+
//#endregion
|
|
199
|
+
//#region ../../libs/execution-plan/src/control-ids.ts
|
|
200
|
+
var CREDENTIAL_AUTHORITY_PREFIX = "credential:";
|
|
201
|
+
var CREDENTIAL_PROJECTION_PREFIX = "credential-projection:";
|
|
202
|
+
var HOST_CAPABILITY_PREFIX = "host-capability:";
|
|
203
|
+
function credentialAuthorityControl(name) {
|
|
204
|
+
return `${CREDENTIAL_AUTHORITY_PREFIX}${name}`;
|
|
205
|
+
}
|
|
206
|
+
function credentialProjectionControl(projection) {
|
|
207
|
+
return `${CREDENTIAL_PROJECTION_PREFIX}${projection}`;
|
|
208
|
+
}
|
|
209
|
+
function hostCapabilityControl(name) {
|
|
210
|
+
return `${HOST_CAPABILITY_PREFIX}${name}`;
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region ../../libs/execution-plan/src/compile-execution-plan.ts
|
|
214
|
+
/**
|
|
215
|
+
* Compile resolved authority and portable intent against one executor offer.
|
|
216
|
+
* The compiler never reads policy identifiers, host bindings, provider
|
|
217
|
+
* coordinates, runtime manifests, or implementation names.
|
|
218
|
+
*/
|
|
219
|
+
function compileExecutionPlan(input) {
|
|
220
|
+
const { intent, offer } = input;
|
|
221
|
+
const stamp = {
|
|
222
|
+
mode: intent.mode,
|
|
223
|
+
phase: "preflight",
|
|
224
|
+
basis: "declared"
|
|
225
|
+
};
|
|
226
|
+
const decisions = [];
|
|
227
|
+
const deliverables = [];
|
|
228
|
+
const readinessByName = uniqueReadiness(input.credentialReadiness);
|
|
229
|
+
const offersByControl = groupOffers(offer.controls);
|
|
230
|
+
const authorized = intent.authority.authorizedControls;
|
|
231
|
+
const networkPatterns = [...intent.network.allowedHosts, ...intent.network.allowedInternalHosts];
|
|
232
|
+
let blocked = false;
|
|
233
|
+
for (const requirement of intent.credentialRequirements) {
|
|
234
|
+
const control = credentialAuthorityControl(requirement.name);
|
|
235
|
+
const fail = (reason, state) => {
|
|
236
|
+
const decisionState = state ?? (requirement.required ? "failed" : "degraded");
|
|
237
|
+
decisions.push({
|
|
238
|
+
control,
|
|
239
|
+
state: decisionState,
|
|
240
|
+
...stamp,
|
|
241
|
+
reason
|
|
242
|
+
});
|
|
243
|
+
blocked ||= requirement.required;
|
|
244
|
+
};
|
|
245
|
+
if (authorized === void 0) {
|
|
246
|
+
fail("credential_authority_unresolved");
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (!authorized.includes(control)) {
|
|
250
|
+
fail("credential_authority_denied");
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const readiness = readinessByName.get(requirement.name);
|
|
254
|
+
if (readiness === void 0) {
|
|
255
|
+
fail("credential_readiness_missing");
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
if (readiness.status !== "ready") {
|
|
259
|
+
fail(readiness.status);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (requirement.destinations.some((destination) => !hostCovered(destination.host, networkPatterns))) {
|
|
263
|
+
fail("destination_not_in_network_intent");
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (requirement.lifecycle !== void 0 && requirement.lifecycle.maxTtlSec > intent.lease.ttlSec) {
|
|
267
|
+
fail("lifecycle_exceeds_lease");
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const offerControl = credentialProjectionControl(requirement.projection);
|
|
271
|
+
const candidates = offersByControl.get(offerControl) ?? [];
|
|
272
|
+
const matchingCandidates = candidates.filter((candidate) => offerContainsRequirement(candidate, requirement));
|
|
273
|
+
if (matchingCandidates.length !== 1) {
|
|
274
|
+
fail(candidates.length === 0 ? "control_not_offered" : matchingCandidates.length === 0 ? "offer_constraints_mismatch" : "offer_ambiguous", "unsupported");
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const candidate = matchingCandidates[0];
|
|
278
|
+
decisions.push({
|
|
279
|
+
control,
|
|
280
|
+
state: "enforced",
|
|
281
|
+
...stamp,
|
|
282
|
+
offerControl,
|
|
283
|
+
enforcement: candidate.enforcement,
|
|
284
|
+
locus: candidate.locus
|
|
285
|
+
});
|
|
286
|
+
deliverables.push({
|
|
287
|
+
name: requirement.name,
|
|
288
|
+
projection: requirement.projection,
|
|
289
|
+
...requirement.projection === "brokered-http" && { guestEnv: requirement.guestEnv },
|
|
290
|
+
required: requirement.required,
|
|
291
|
+
destinations: cloneDestinations(requirement.destinations),
|
|
292
|
+
offerControl,
|
|
293
|
+
enforcement: candidate.enforcement,
|
|
294
|
+
locus: candidate.locus
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
for (const name of intent.requiredCapabilities) {
|
|
298
|
+
const control = hostCapabilityControl(name);
|
|
299
|
+
if (authorized === void 0) {
|
|
300
|
+
decisions.push({
|
|
301
|
+
control,
|
|
302
|
+
state: "failed",
|
|
303
|
+
...stamp,
|
|
304
|
+
reason: "capability_authority_unresolved"
|
|
305
|
+
});
|
|
306
|
+
blocked = true;
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (!authorized.includes(control)) {
|
|
310
|
+
decisions.push({
|
|
311
|
+
control,
|
|
312
|
+
state: "failed",
|
|
313
|
+
...stamp,
|
|
314
|
+
reason: "capability_authority_denied"
|
|
315
|
+
});
|
|
316
|
+
blocked = true;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
const candidates = offersByControl.get(control) ?? [];
|
|
320
|
+
if (candidates.length !== 1) {
|
|
321
|
+
decisions.push({
|
|
322
|
+
control,
|
|
323
|
+
state: "unsupported",
|
|
324
|
+
...stamp,
|
|
325
|
+
reason: candidates.length === 0 ? "control_not_offered" : "offer_ambiguous"
|
|
326
|
+
});
|
|
327
|
+
blocked = true;
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
const candidate = candidates[0];
|
|
331
|
+
decisions.push({
|
|
332
|
+
control,
|
|
333
|
+
state: "enforced",
|
|
334
|
+
...stamp,
|
|
335
|
+
offerControl: candidate.id,
|
|
336
|
+
enforcement: candidate.enforcement,
|
|
337
|
+
locus: candidate.locus
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
for (const control of intent.lease.requiredControls) {
|
|
341
|
+
const candidates = offersByControl.get(control) ?? [];
|
|
342
|
+
if (candidates.length !== 1) {
|
|
343
|
+
decisions.push({
|
|
344
|
+
control,
|
|
345
|
+
state: "unsupported",
|
|
346
|
+
...stamp,
|
|
347
|
+
reason: candidates.length === 0 ? "control_not_offered" : "offer_ambiguous"
|
|
348
|
+
});
|
|
349
|
+
blocked = true;
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
const candidate = candidates[0];
|
|
353
|
+
decisions.push({
|
|
354
|
+
control,
|
|
355
|
+
state: "enforced",
|
|
356
|
+
...stamp,
|
|
357
|
+
offerControl: candidate.id,
|
|
358
|
+
enforcement: candidate.enforcement,
|
|
359
|
+
locus: candidate.locus
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
mode: intent.mode,
|
|
364
|
+
launchable: !blocked,
|
|
365
|
+
executor: { ...offer.executor },
|
|
366
|
+
decisions,
|
|
367
|
+
deliverables,
|
|
368
|
+
effectiveNetwork: {
|
|
369
|
+
allowedHosts: [...new Set(intent.network.allowedHosts)].sort(),
|
|
370
|
+
allowedInternalHosts: [...new Set(intent.network.allowedInternalHosts)].sort()
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function groupOffers(controls) {
|
|
375
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
376
|
+
for (const control of controls) {
|
|
377
|
+
const existing = grouped.get(control.id) ?? [];
|
|
378
|
+
existing.push(control);
|
|
379
|
+
grouped.set(control.id, existing);
|
|
380
|
+
}
|
|
381
|
+
return grouped;
|
|
382
|
+
}
|
|
383
|
+
function uniqueReadiness(readiness) {
|
|
384
|
+
const result = /* @__PURE__ */ new Map();
|
|
385
|
+
for (const record of readiness) {
|
|
386
|
+
if (result.has(record.name)) throw new Error(`duplicate credential readiness for "${record.name}"`);
|
|
387
|
+
result.set(record.name, record);
|
|
388
|
+
}
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
function offerContainsRequirement(offer, requirement) {
|
|
392
|
+
const offeredDestinations = offer.constraints?.destinations;
|
|
393
|
+
if (offeredDestinations === void 0 || !sameDestinationSet(offeredDestinations, requirement.destinations)) return false;
|
|
394
|
+
if (requirement.projection === "brokered-http") return offer.constraints?.guestEnvs?.includes(requirement.guestEnv) ?? false;
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
function sameDestinationSet(offered, requested) {
|
|
398
|
+
const offeredKeys = offered.map(destinationKey).sort();
|
|
399
|
+
const requestedKeys = requested.map(destinationKey).sort();
|
|
400
|
+
return offeredKeys.length === requestedKeys.length && offeredKeys.every((key, index) => key === requestedKeys[index]);
|
|
401
|
+
}
|
|
402
|
+
function destinationKey(destination) {
|
|
403
|
+
return `${destination.protocol}\0${destination.host}\0${destination.port}`;
|
|
404
|
+
}
|
|
405
|
+
function cloneDestinations(destinations) {
|
|
406
|
+
return destinations.map((destination) => ({ ...destination }));
|
|
407
|
+
}
|
|
408
|
+
/** Exact host, or a profile wildcard covering one or more subdomains. */
|
|
409
|
+
function hostCovered(host, patterns) {
|
|
410
|
+
return patterns.some((pattern) => {
|
|
411
|
+
if (pattern === host) return true;
|
|
412
|
+
if (!pattern.startsWith("*.")) return false;
|
|
413
|
+
const suffix = pattern.slice(1);
|
|
414
|
+
return host.endsWith(suffix) && host.length > suffix.length;
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
//#endregion
|
|
418
|
+
//#region ../../libs/execution-plan/src/credential-requirements.ts
|
|
419
|
+
var CredentialDestination = Type.Object({
|
|
420
|
+
protocol: Type.Union([Type.Literal("https"), Type.Literal("http")]),
|
|
421
|
+
host: Type.String({
|
|
422
|
+
minLength: 1,
|
|
423
|
+
maxLength: 255,
|
|
424
|
+
pattern: "^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))*$"
|
|
425
|
+
}),
|
|
426
|
+
port: Type.Integer({
|
|
427
|
+
minimum: 1,
|
|
428
|
+
maximum: 65535
|
|
429
|
+
})
|
|
430
|
+
}, { additionalProperties: false });
|
|
431
|
+
var GuestEnvName = Type.String({
|
|
432
|
+
minLength: 1,
|
|
433
|
+
maxLength: 128,
|
|
434
|
+
pattern: "^(?!MOLTNET_)[A-Z][A-Z0-9_]*$"
|
|
435
|
+
});
|
|
436
|
+
var CredentialLifecycleIntent = Type.Object({
|
|
437
|
+
maxTtlSec: Type.Integer({
|
|
438
|
+
minimum: 1,
|
|
439
|
+
maximum: 86400
|
|
440
|
+
}),
|
|
441
|
+
refreshBeforeSec: Type.Integer({
|
|
442
|
+
minimum: 1,
|
|
443
|
+
maximum: 86400
|
|
444
|
+
})
|
|
445
|
+
}, { additionalProperties: false });
|
|
446
|
+
var credentialRequirementBase = {
|
|
447
|
+
name: Type.String({ minLength: 1 }),
|
|
448
|
+
kind: Type.Union([
|
|
449
|
+
Type.Literal("http-bearer"),
|
|
450
|
+
Type.Literal("http-basic"),
|
|
451
|
+
Type.Literal("api-key-header")
|
|
452
|
+
]),
|
|
453
|
+
destinations: Type.Array(CredentialDestination, { minItems: 1 }),
|
|
454
|
+
required: Type.Boolean({ default: true }),
|
|
455
|
+
lifecycle: Type.Optional(CredentialLifecycleIntent)
|
|
456
|
+
};
|
|
457
|
+
var HostToolCredentialRequirement = Type.Object({
|
|
458
|
+
...credentialRequirementBase,
|
|
459
|
+
projection: Type.Literal("host-tool")
|
|
460
|
+
}, { additionalProperties: false });
|
|
461
|
+
var BrokeredHttpCredentialRequirement = Type.Object({
|
|
462
|
+
...credentialRequirementBase,
|
|
463
|
+
projection: Type.Literal("brokered-http"),
|
|
464
|
+
guestEnv: GuestEnvName
|
|
465
|
+
}, { additionalProperties: false });
|
|
466
|
+
var CredentialRequirement = Type.Union([HostToolCredentialRequirement, BrokeredHttpCredentialRequirement]);
|
|
467
|
+
function parseCredentialRequirements(input) {
|
|
468
|
+
const withDefaults = Value.Default(Type.Array(CredentialRequirement), Value.Clone(input));
|
|
469
|
+
const requirements = Value.Parse(Type.Array(CredentialRequirement), withDefaults);
|
|
470
|
+
const names = /* @__PURE__ */ new Set();
|
|
471
|
+
const guestEnvs = /* @__PURE__ */ new Set();
|
|
472
|
+
for (const requirement of requirements) {
|
|
473
|
+
if (names.has(requirement.name)) throw new Error(`duplicate credential requirement name "${requirement.name}"`);
|
|
474
|
+
names.add(requirement.name);
|
|
475
|
+
if (requirement.projection === "brokered-http") {
|
|
476
|
+
if (guestEnvs.has(requirement.guestEnv)) throw new Error(`duplicate brokered guestEnv "${requirement.guestEnv}"`);
|
|
477
|
+
guestEnvs.add(requirement.guestEnv);
|
|
478
|
+
}
|
|
479
|
+
const lifecycle = requirement.lifecycle;
|
|
480
|
+
if (lifecycle && lifecycle.refreshBeforeSec >= lifecycle.maxTtlSec) throw new Error(`credential requirement "${requirement.name}": refreshBeforeSec must be shorter than maxTtlSec`);
|
|
481
|
+
}
|
|
482
|
+
return requirements;
|
|
483
|
+
}
|
|
484
|
+
//#endregion
|
|
485
|
+
//#region ../../libs/execution-plan/src/execution-snapshot.ts
|
|
486
|
+
/**
|
|
487
|
+
* Create an immutable, content-addressed, value-free execution snapshot. The
|
|
488
|
+
* existing policy snapshot hash is pinned inside intent; policy composition
|
|
489
|
+
* has already happened before this boundary.
|
|
490
|
+
*/
|
|
491
|
+
async function createExecutionPlanSnapshot(input) {
|
|
492
|
+
const body = structuredClone(input);
|
|
493
|
+
return deepFreeze({
|
|
494
|
+
cid: await computeJsonCid(snapshotBody(body)),
|
|
495
|
+
...body
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
function snapshotBody(input) {
|
|
499
|
+
return {
|
|
500
|
+
v: "moltnet:execution-plan-snapshot:v1",
|
|
501
|
+
...input
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function deepFreeze(value) {
|
|
505
|
+
if (value !== null && typeof value === "object") {
|
|
506
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
507
|
+
Object.freeze(value);
|
|
508
|
+
}
|
|
509
|
+
return value;
|
|
510
|
+
}
|
|
511
|
+
//#endregion
|
|
512
|
+
//#region src/lib/runtime-governance.ts
|
|
513
|
+
var executionOffers = /* @__PURE__ */ new WeakMap();
|
|
514
|
+
/** Attach private governance metadata without widening the public adapter API. */
|
|
515
|
+
function registerRuntimeExecutionOffer(runtime, factory) {
|
|
516
|
+
executionOffers.set(runtime, factory);
|
|
517
|
+
}
|
|
518
|
+
/** Resolve the selected runtime's offer for the observe-only orchestrator. */
|
|
519
|
+
function runtimeExecutionOffer(runtime, executorFingerprint) {
|
|
520
|
+
return executionOffers.get(runtime)?.(executorFingerprint);
|
|
521
|
+
}
|
|
522
|
+
//#endregion
|
|
523
|
+
//#region ../../libs/execution-integrations/src/pi.ts
|
|
524
|
+
/** Convert the canonical Pi manifest to a portable, open-ended offer. */
|
|
525
|
+
function executionCapabilityOfferFromPiManifest(manifest, options) {
|
|
526
|
+
const enforcement = options.enforcement ?? "native";
|
|
527
|
+
const locus = options.locus ?? "pi:isolated-runtime";
|
|
528
|
+
return {
|
|
529
|
+
executor: {
|
|
530
|
+
id: `${manifest.runtime.id}@${manifest.runtime.version}`,
|
|
531
|
+
fingerprint: options.executorFingerprint
|
|
532
|
+
},
|
|
533
|
+
controls: [...(manifest.brokeredHttpSecrets ?? []).map((secret) => ({
|
|
534
|
+
id: credentialProjectionControl("brokered-http"),
|
|
535
|
+
enforcement,
|
|
536
|
+
locus,
|
|
537
|
+
constraints: {
|
|
538
|
+
destinations: manifestDestinations(secret),
|
|
539
|
+
guestEnvs: [secret.guestEnv]
|
|
540
|
+
}
|
|
541
|
+
})), ...(manifest.hostCapabilities ?? []).map((capability) => ({
|
|
542
|
+
id: hostCapabilityControl(capability.name),
|
|
543
|
+
enforcement,
|
|
544
|
+
locus
|
|
545
|
+
}))]
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
function manifestDestinations(secret) {
|
|
549
|
+
return secret.hosts.flatMap((host) => secret.ports.map((port) => ({
|
|
550
|
+
protocol: secret.protocol,
|
|
551
|
+
host,
|
|
552
|
+
port
|
|
553
|
+
})));
|
|
554
|
+
}
|
|
555
|
+
//#endregion
|
|
3
556
|
//#region src/pi.ts
|
|
4
557
|
var PI_KERNEL_TOOL_NAMES = [
|
|
5
558
|
...GONDOLIN_TOOL_NAMES,
|
|
@@ -29,7 +582,7 @@ function createPiDaemonAdapter(runtime) {
|
|
|
29
582
|
builtInToolNames: PI_KERNEL_TOOL_NAMES
|
|
30
583
|
});
|
|
31
584
|
const extensionTools = runtime.extensions.flatMap((extension) => extension.declaredTools);
|
|
32
|
-
|
|
585
|
+
const prepared = {
|
|
33
586
|
runtimeKind: runtime.runtimeKind,
|
|
34
587
|
manifest,
|
|
35
588
|
tools: [
|
|
@@ -49,6 +602,8 @@ function createPiDaemonAdapter(runtime) {
|
|
|
49
602
|
resolvedVmTemplate: resolvedTemplate
|
|
50
603
|
})
|
|
51
604
|
};
|
|
605
|
+
registerRuntimeExecutionOffer(prepared, (executorFingerprint) => executionCapabilityOfferFromPiManifest(manifest, { executorFingerprint }));
|
|
606
|
+
return prepared;
|
|
52
607
|
}
|
|
53
608
|
};
|
|
54
609
|
}
|
|
@@ -64,4 +619,4 @@ var defaultPiRuntimeDefinition = definePiRuntime({
|
|
|
64
619
|
});
|
|
65
620
|
var defaultPiDaemonAdapter = createPiDaemonAdapter(defaultPiRuntimeDefinition);
|
|
66
621
|
//#endregion
|
|
67
|
-
export { PI_KERNEL_TOOL_NAMES, createPiDaemonAdapter, defaultPiDaemonAdapter, defaultPiRuntimeDefinition };
|
|
622
|
+
export { PI_KERNEL_TOOL_NAMES, cryptoService as a, createPiDaemonAdapter, defaultPiDaemonAdapter, defaultPiRuntimeDefinition, compileExecutionPlan as i, createExecutionPlanSnapshot as n, parseCredentialRequirements as r, runtimeExecutionOffer as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/agent-daemon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.1",
|
|
4
4
|
"license": "AGPL-3.0-only",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Universal MoltNet agent daemon host with a built-in Pi/Gondolin runtime and support for trusted operator-owned runtime modules. CLI: moltnet-agent.",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"@noble/curves": "^2.0.0",
|
|
57
57
|
"@noble/ed25519": "^2.0.0",
|
|
58
58
|
"@noble/hashes": "^1.7.0",
|
|
59
|
-
"@opentelemetry/api": "^1.9.
|
|
59
|
+
"@opentelemetry/api": "^1.9.1",
|
|
60
60
|
"@opentelemetry/exporter-metrics-otlp-proto": "^0.212.0",
|
|
61
61
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.212.0",
|
|
62
62
|
"@opentelemetry/instrumentation": "^0.212.0",
|
|
@@ -78,10 +78,10 @@
|
|
|
78
78
|
"pino-opentelemetry-transport": "^3.0.0",
|
|
79
79
|
"pino-pretty": "^13.1.3",
|
|
80
80
|
"typebox": "^1.2.8",
|
|
81
|
+
"@themoltnet/agent-runtime": "0.45.1",
|
|
82
|
+
"@themoltnet/sdk": "0.139.0",
|
|
81
83
|
"@themoltnet/os-keyring": "0.3.0",
|
|
82
|
-
"@themoltnet/
|
|
83
|
-
"@themoltnet/pi-runtime": "0.12.2",
|
|
84
|
-
"@themoltnet/sdk": "0.138.0"
|
|
84
|
+
"@themoltnet/pi-runtime": "0.13.1"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"tsx": "^4.7.0",
|
|
@@ -89,9 +89,11 @@
|
|
|
89
89
|
"vite": "^8.0.0",
|
|
90
90
|
"vite-plugin-dts": "^4.5.4",
|
|
91
91
|
"vitest": "^3.0.0",
|
|
92
|
-
"@moltnet/bootstrap": "0.1.0",
|
|
93
92
|
"@moltnet/crypto-service": "0.1.0",
|
|
93
|
+
"@moltnet/bootstrap": "0.1.0",
|
|
94
|
+
"@moltnet/execution-integrations": "0.1.0",
|
|
94
95
|
"@moltnet/models": "0.1.0",
|
|
96
|
+
"@moltnet/execution-plan": "0.1.0",
|
|
95
97
|
"@moltnet/observability": "0.1.0",
|
|
96
98
|
"@moltnet/runtime-profiles": "0.1.0",
|
|
97
99
|
"@moltnet/tasks": "0.1.0"
|