@themoltnet/agent-daemon 0.54.0 → 0.55.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 +115 -175
- package/package.json +9 -9
package/dist/cli.js
CHANGED
|
@@ -13,8 +13,8 @@ import { parseArgs, promisify } from "node:util";
|
|
|
13
13
|
import { AgentRuntime, ApiTaskReporter, ApiTaskSource, PollingApiTaskSource, createLocalSeedSigner, resolveAgentIdentity, resolveProfileWarmSessionTtlSec, resolveRuntimeProfile, resolveRuntimeProfiles, validateRuntimeProfilePrerequisites } from "@themoltnet/agent-runtime";
|
|
14
14
|
import { GuestEnvironmentBoundaryError, assertGuestEnvironmentBoundary, createPiRetryTriage, findMainWorktree, isResolvedPathInsideRoot, normalizeRetryTriageResult, redactRetryTriageSecrets, resolveRuntimeProfileModel } from "@themoltnet/pi-runtime";
|
|
15
15
|
import { FILE_SECRET_PROVIDER, FileSecretProvider, connect, createNodeSecretProviderRegistry } from "@themoltnet/sdk/node";
|
|
16
|
-
import { constants,
|
|
17
|
-
import { AuthenticationError, IDENTITY_ALIAS_PATTERN, MoltNetError, agentKeyKey, assertIdentityAlias, assertTrustedConfigApiUrl, createExecutorAttestor, deriveMcpUrl, formatSecretReferenceString, getConfigDir, getIdentityDir, identitySeedKey, parseSecretReferenceString, readConfig, register, requireSecureCredentialApiUrl, resolveAgentKey, resolveEnvSecretReference, resolveIdentitySeed
|
|
16
|
+
import { constants, createReadStream, createWriteStream, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
17
|
+
import { AuthenticationError, IDENTITY_ALIAS_PATTERN, MoltNetError, agentKeyKey, assertIdentityAlias, assertTrustedConfigApiUrl, createExecutorAttestor, deriveMcpUrl, formatSecretReferenceString, getConfigDir, getIdentityDir, identitySeedKey, isCanonicalConfig, parseSecretReferenceString, readConfig, register, requireSecureCredentialApiUrl, resolveAgentKey, resolveEnvSecretReference, resolveIdentitySeed } from "@themoltnet/sdk";
|
|
18
18
|
import { execFile, spawn } from "node:child_process";
|
|
19
19
|
import { X509Certificate, createHash, createPrivateKey, createPublicKey, randomBytes, randomUUID, timingSafeEqual, webcrypto } from "node:crypto";
|
|
20
20
|
import { once } from "node:events";
|
|
@@ -1363,7 +1363,8 @@ Type.Object({ "x-moltnet-team-id": Type.Optional(Type.String({
|
|
|
1363
1363
|
})) });
|
|
1364
1364
|
Type.Object({
|
|
1365
1365
|
kind: Type.Literal("agent"),
|
|
1366
|
-
|
|
1366
|
+
agentId: UuidSchema,
|
|
1367
|
+
identityId: Type.Union([UuidSchema, Type.Null()]),
|
|
1367
1368
|
fingerprint: FingerprintSchema,
|
|
1368
1369
|
publicKey: PublicKeySchema
|
|
1369
1370
|
}, {
|
|
@@ -1380,7 +1381,8 @@ Type.Object({
|
|
|
1380
1381
|
});
|
|
1381
1382
|
var principalUnionVariants = [Type.Object({
|
|
1382
1383
|
kind: Type.Literal("agent"),
|
|
1383
|
-
|
|
1384
|
+
agentId: UuidSchema,
|
|
1385
|
+
identityId: Type.Union([UuidSchema, Type.Null()]),
|
|
1384
1386
|
fingerprint: FingerprintSchema,
|
|
1385
1387
|
publicKey: PublicKeySchema
|
|
1386
1388
|
}, { additionalProperties: false }), Type.Object({
|
|
@@ -3408,8 +3410,8 @@ var COMMON_OPTIONAL_FLAGS = `\
|
|
|
3408
3410
|
--git-author <"Name <email>">
|
|
3409
3411
|
Non-secret git identity projected into the
|
|
3410
3412
|
guest for host-brokered commit signing. Default:
|
|
3411
|
-
host git config
|
|
3412
|
-
|
|
3413
|
+
host git config. Configless agent-key runs must
|
|
3414
|
+
provide this flag or MOLTNET_GIT_AUTHOR.
|
|
3413
3415
|
Env: MOLTNET_GIT_AUTHOR.
|
|
3414
3416
|
--lease-ttl-sec <n> Sliding liveness window. Silence longer than
|
|
3415
3417
|
this ends the attempt with lease_expired.
|
|
@@ -3626,8 +3628,17 @@ remove that exact CA. Linux continues to use the Chromium PNA HTTP path.
|
|
|
3626
3628
|
//#region src/lib/identity-pin.ts
|
|
3627
3629
|
/** Compare every pinned field without choosing a caller-specific error type. */
|
|
3628
3630
|
function assessIdentityPin(current, expected) {
|
|
3631
|
+
for (const [field, label] of [["publicKey", "public key"], ["fingerprint", "fingerprint"]]) if (!current[field] || current[field] !== expected[field]) return {
|
|
3632
|
+
ok: false,
|
|
3633
|
+
field,
|
|
3634
|
+
label
|
|
3635
|
+
};
|
|
3636
|
+
return { ok: true };
|
|
3637
|
+
}
|
|
3638
|
+
function assessAgentStartupPin(current, expected) {
|
|
3629
3639
|
for (const [field, label] of [
|
|
3630
|
-
["
|
|
3640
|
+
["subjectId", "subject id"],
|
|
3641
|
+
["subjectType", "subject type"],
|
|
3631
3642
|
["publicKey", "public key"],
|
|
3632
3643
|
["fingerprint", "fingerprint"]
|
|
3633
3644
|
]) if (!current[field] || current[field] !== expected[field]) return {
|
|
@@ -3712,8 +3723,8 @@ async function validateStartupBinding(options) {
|
|
|
3712
3723
|
}
|
|
3713
3724
|
const assessment = assessStartupBinding(whoami, options.teamId);
|
|
3714
3725
|
if (!assessment.ok) throw new Error(`Daemon startup validation failed: ${assessment.reason}`);
|
|
3715
|
-
const expected = options.
|
|
3716
|
-
if (expected && !
|
|
3726
|
+
const expected = options.expectedAgent;
|
|
3727
|
+
if (expected && !assessAgentStartupPin(whoami, expected).ok) throw new Error("Daemon startup validation failed: authenticated agent does not match the Agent Server activation.");
|
|
3717
3728
|
return whoami;
|
|
3718
3729
|
}
|
|
3719
3730
|
/**
|
|
@@ -3843,7 +3854,7 @@ function isTransientWhoamiError(error) {
|
|
|
3843
3854
|
function loadConfig() {
|
|
3844
3855
|
assertSingleCredentialForm("MOLTNET_AGENT_KEY", "MOLTNET_AGENT_KEY_REF");
|
|
3845
3856
|
assertSingleCredentialForm("MOLTNET_PRIVATE_KEY", "MOLTNET_PRIVATE_KEY_REF");
|
|
3846
|
-
const
|
|
3857
|
+
const expectedAgent = readExpectedAgent();
|
|
3847
3858
|
return {
|
|
3848
3859
|
otelEndpoint: process.env["MOLTNET_OTEL_ENDPOINT"] ?? "",
|
|
3849
3860
|
logLevel: process.env["LOG_LEVEL"] ?? "",
|
|
@@ -3859,22 +3870,27 @@ function loadConfig() {
|
|
|
3859
3870
|
credentialBindings: process.env["MOLTNET_CREDENTIAL_BINDINGS"] ?? "",
|
|
3860
3871
|
credentialEnforcement: process.env["MOLTNET_CREDENTIAL_ENFORCEMENT"] ?? "",
|
|
3861
3872
|
traceIdlePolling: readBoolean("MOLTNET_TRACE_IDLE_POLLING", process.env["MOLTNET_TRACE_IDLE_POLLING"]),
|
|
3862
|
-
...
|
|
3873
|
+
...expectedAgent ? { expectedAgent } : {}
|
|
3863
3874
|
};
|
|
3864
3875
|
}
|
|
3865
|
-
function
|
|
3866
|
-
|
|
3876
|
+
function readExpectedAgent() {
|
|
3877
|
+
if (process.env["MOLTNET_EXPECTED_IDENTITY_ID"]?.trim()) throw new Error("MOLTNET_EXPECTED_IDENTITY_ID is no longer supported; set the complete MOLTNET_EXPECTED_SUBJECT_ID, MOLTNET_EXPECTED_SUBJECT_TYPE=agent, MOLTNET_EXPECTED_PUBLIC_KEY, and MOLTNET_EXPECTED_FINGERPRINT pin");
|
|
3878
|
+
const subjectId = process.env["MOLTNET_EXPECTED_SUBJECT_ID"]?.trim() ?? "";
|
|
3879
|
+
const subjectType = process.env["MOLTNET_EXPECTED_SUBJECT_TYPE"]?.trim() ?? "";
|
|
3867
3880
|
const publicKey = process.env["MOLTNET_EXPECTED_PUBLIC_KEY"]?.trim() ?? "";
|
|
3868
3881
|
const fingerprint = process.env["MOLTNET_EXPECTED_FINGERPRINT"]?.trim() ?? "";
|
|
3869
3882
|
const present = [
|
|
3870
|
-
|
|
3883
|
+
subjectId,
|
|
3884
|
+
subjectType,
|
|
3871
3885
|
publicKey,
|
|
3872
3886
|
fingerprint
|
|
3873
3887
|
].filter(Boolean).length;
|
|
3874
3888
|
if (present === 0) return void 0;
|
|
3875
|
-
if (present !==
|
|
3889
|
+
if (present !== 4) throw new Error("MOLTNET_EXPECTED_SUBJECT_ID, MOLTNET_EXPECTED_SUBJECT_TYPE, MOLTNET_EXPECTED_PUBLIC_KEY, and MOLTNET_EXPECTED_FINGERPRINT must be set together");
|
|
3890
|
+
if (subjectType !== "agent") throw new Error("MOLTNET_EXPECTED_SUBJECT_TYPE must be agent");
|
|
3876
3891
|
return {
|
|
3877
|
-
|
|
3892
|
+
subjectId,
|
|
3893
|
+
subjectType,
|
|
3878
3894
|
publicKey,
|
|
3879
3895
|
fingerprint
|
|
3880
3896
|
};
|
|
@@ -3896,7 +3912,6 @@ function loadAgentServerEnvConfig() {
|
|
|
3896
3912
|
port: process.env["MOLTNET_AGENT_SERVER_PORT"] ?? "",
|
|
3897
3913
|
allowedOrigins: process.env["MOLTNET_AGENT_SERVER_ALLOWED_ORIGINS"] ?? "",
|
|
3898
3914
|
root: process.env["MOLTNET_AGENT_SERVER_ROOT"] ?? "",
|
|
3899
|
-
xdgConfigHome: process.env["XDG_CONFIG_HOME"] ?? "",
|
|
3900
3915
|
apiUrl: process.env["MOLTNET_API_URL"] ?? "",
|
|
3901
3916
|
logLevel: process.env["LOG_LEVEL"] ?? ""
|
|
3902
3917
|
};
|
|
@@ -5277,16 +5292,16 @@ function validateTaskTypes(types) {
|
|
|
5277
5292
|
/**
|
|
5278
5293
|
* OTel SDK bootstrap for the agent daemon.
|
|
5279
5294
|
*
|
|
5280
|
-
* const shutdown = await initWorkerOtel({ serviceName,
|
|
5295
|
+
* const shutdown = await initWorkerOtel({ serviceName, agent });
|
|
5281
5296
|
* try { ... } finally { await shutdown(); }
|
|
5282
5297
|
*
|
|
5283
5298
|
* No-op when MOLTNET_OTEL_ENDPOINT is unset — `@opentelemetry/api` falls
|
|
5284
5299
|
* back to no-op tracers and meters, so the runtime + pi extension still
|
|
5285
5300
|
* call into it but nothing is exported.
|
|
5286
5301
|
*/
|
|
5287
|
-
|
|
5302
|
+
function initWorkerOtel(options) {
|
|
5288
5303
|
const endpoint = options.endpoint;
|
|
5289
|
-
if (!endpoint) return async () => {};
|
|
5304
|
+
if (!endpoint) return Promise.resolve(async () => {});
|
|
5290
5305
|
const resource = resourceFromAttributes({
|
|
5291
5306
|
[ATTR_SERVICE_NAME]: options.serviceName,
|
|
5292
5307
|
...options.serviceVersion && { [ATTR_SERVICE_VERSION]: options.serviceVersion },
|
|
@@ -5294,11 +5309,7 @@ async function initWorkerOtel(options) {
|
|
|
5294
5309
|
...options.resourceAttributes
|
|
5295
5310
|
});
|
|
5296
5311
|
let headersFactory;
|
|
5297
|
-
|
|
5298
|
-
if (!agent && options.agentDir) agent = await connect({
|
|
5299
|
-
configDir: options.agentDir,
|
|
5300
|
-
secretProviders: createNodeSecretProviderRegistry()
|
|
5301
|
-
});
|
|
5312
|
+
const agent = options.agent;
|
|
5302
5313
|
if (agent) headersFactory = async () => {
|
|
5303
5314
|
return { Authorization: `Bearer ${await agent.getToken()}` };
|
|
5304
5315
|
};
|
|
@@ -5323,7 +5334,7 @@ async function initWorkerOtel(options) {
|
|
|
5323
5334
|
});
|
|
5324
5335
|
provider.register();
|
|
5325
5336
|
metrics.setGlobalMeterProvider(meterProvider);
|
|
5326
|
-
return async () => {
|
|
5337
|
+
return Promise.resolve(async () => {
|
|
5327
5338
|
await Promise.all([provider.forceFlush().catch((err) => {
|
|
5328
5339
|
process.stderr.write(`[otel-bootstrap] trace forceFlush failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
5329
5340
|
}), meterProvider.forceFlush().catch((err) => {
|
|
@@ -5334,7 +5345,7 @@ async function initWorkerOtel(options) {
|
|
|
5334
5345
|
}), meterProvider.shutdown().catch((err) => {
|
|
5335
5346
|
process.stderr.write(`[otel-bootstrap] metric shutdown failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
5336
5347
|
})]);
|
|
5337
|
-
};
|
|
5348
|
+
});
|
|
5338
5349
|
}
|
|
5339
5350
|
//#endregion
|
|
5340
5351
|
//#region src/lib/pi-agent-dir.ts
|
|
@@ -6024,7 +6035,7 @@ async function runPolling(opts) {
|
|
|
6024
6035
|
const whoami = await validateStartupBinding({
|
|
6025
6036
|
agent: resolvedContext.agent,
|
|
6026
6037
|
teamId,
|
|
6027
|
-
|
|
6038
|
+
expectedAgent: cfg.expectedAgent
|
|
6028
6039
|
});
|
|
6029
6040
|
gate = "resolve_signing_material";
|
|
6030
6041
|
const privateKey = await resolveExecutorSigningPrivateKey({
|
|
@@ -6071,11 +6082,12 @@ async function runPolling(opts) {
|
|
|
6071
6082
|
throw error;
|
|
6072
6083
|
}
|
|
6073
6084
|
})();
|
|
6085
|
+
const daemonRootDir = explicitAgentRootDir ?? process.cwd();
|
|
6074
6086
|
const resolvedProfiles = await resolveRuntimeProfiles({
|
|
6075
6087
|
agent: ctx.agent,
|
|
6076
6088
|
profiles: profileValues,
|
|
6077
6089
|
teamId,
|
|
6078
|
-
cwd:
|
|
6090
|
+
cwd: daemonRootDir
|
|
6079
6091
|
});
|
|
6080
6092
|
const runtimeAdapter = opts.runtimeAdapter ?? defaultPiDaemonAdapter;
|
|
6081
6093
|
const preparedRuntimes = /* @__PURE__ */ new Map();
|
|
@@ -6682,7 +6694,7 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
|
|
|
6682
6694
|
const whoami = await validateStartupBinding({
|
|
6683
6695
|
agent: resolvedContext.agent,
|
|
6684
6696
|
teamId: values.team,
|
|
6685
|
-
|
|
6697
|
+
expectedAgent: cfg.expectedAgent
|
|
6686
6698
|
});
|
|
6687
6699
|
gate = "resolve_signing_material";
|
|
6688
6700
|
const privateKey = await resolveExecutorSigningPrivateKey({
|
|
@@ -6728,11 +6740,12 @@ async function runOnce(argv, runtimeAdapter = defaultPiDaemonAdapter) {
|
|
|
6728
6740
|
throw error;
|
|
6729
6741
|
}
|
|
6730
6742
|
})();
|
|
6743
|
+
const daemonRootDir = explicitAgentRootDir ?? process.cwd();
|
|
6731
6744
|
const profile = await resolveRuntimeProfile({
|
|
6732
6745
|
agent: ctx.agent,
|
|
6733
6746
|
profile: values.profile,
|
|
6734
6747
|
teamId: values.team,
|
|
6735
|
-
cwd:
|
|
6748
|
+
cwd: daemonRootDir
|
|
6736
6749
|
});
|
|
6737
6750
|
assertRuntimeAdapterSupportsProfile(runtimeAdapter, profile);
|
|
6738
6751
|
const preparedRuntime = attestPreparedRuntime(await runtimeAdapter.prepare({ profile }), signingPrivateKey);
|
|
@@ -7869,39 +7882,13 @@ var AgentServerStoreError = class extends Error {
|
|
|
7869
7882
|
* so honouring XDG here gave one application two config roots: on a machine
|
|
7870
7883
|
* with the variable set, the daemon wrote identities the CLI and SDK could not
|
|
7871
7884
|
* read. `MOLTNET_AGENT_SERVER_ROOT` remains the explicit escape hatch for a
|
|
7872
|
-
* genuinely custom location.
|
|
7873
|
-
* accepted-but-discarded argument reads like it still works. Callers adopting
|
|
7874
|
-
* state from the old root pass it to ensure() instead.
|
|
7885
|
+
* genuinely custom location.
|
|
7875
7886
|
*/
|
|
7876
7887
|
function resolveAgentServerRoot(input) {
|
|
7877
7888
|
const override = input.root?.trim();
|
|
7878
7889
|
if (override) return override;
|
|
7879
7890
|
return getConfigDir();
|
|
7880
7891
|
}
|
|
7881
|
-
/** The pre-#1834 root that honoured XDG_CONFIG_HOME, if it differs. */
|
|
7882
|
-
function legacyXdgAgentServerRoot(xdgConfigHome) {
|
|
7883
|
-
const xdg = xdgConfigHome.trim();
|
|
7884
|
-
if (!xdg) return null;
|
|
7885
|
-
const legacy = join(xdg, "moltnet");
|
|
7886
|
-
return legacy === resolveAgentServerRoot({}) ? null : legacy;
|
|
7887
|
-
}
|
|
7888
|
-
/** True when a root holds agent-server state worth preserving. */
|
|
7889
|
-
function hasAgentServerState(root) {
|
|
7890
|
-
for (const child of [
|
|
7891
|
-
"agent-server.json",
|
|
7892
|
-
"identity-selector.json",
|
|
7893
|
-
"identities",
|
|
7894
|
-
"agents"
|
|
7895
|
-
]) try {
|
|
7896
|
-
if (readdirSync(join(root, child)).length > 0) return true;
|
|
7897
|
-
} catch {
|
|
7898
|
-
try {
|
|
7899
|
-
readFileSync(join(root, child));
|
|
7900
|
-
return true;
|
|
7901
|
-
} catch {}
|
|
7902
|
-
}
|
|
7903
|
-
return false;
|
|
7904
|
-
}
|
|
7905
7892
|
function providerEnvName(providerId) {
|
|
7906
7893
|
return `MOLTNET_PROVIDER_${assertProviderId(providerId).replaceAll("-", "_").toUpperCase()}_API_KEY`;
|
|
7907
7894
|
}
|
|
@@ -7954,8 +7941,7 @@ var AgentServerStore = class {
|
|
|
7954
7941
|
return join(this.piDir, "auth.json");
|
|
7955
7942
|
}
|
|
7956
7943
|
/** Create the directory layout (0700) if missing. Idempotent. */
|
|
7957
|
-
ensure(
|
|
7958
|
-
this.adoptLegacyXdgRoot(options.legacyXdgConfigHome ?? "");
|
|
7944
|
+
ensure() {
|
|
7959
7945
|
for (const dir of [
|
|
7960
7946
|
this.root,
|
|
7961
7947
|
this.identitiesDir,
|
|
@@ -7965,94 +7951,28 @@ var AgentServerStore = class {
|
|
|
7965
7951
|
recursive: true,
|
|
7966
7952
|
mode: 448
|
|
7967
7953
|
});
|
|
7968
|
-
this.migrateLegacyAgentDocuments();
|
|
7969
7954
|
return this;
|
|
7970
7955
|
}
|
|
7971
|
-
/**
|
|
7972
|
-
* Adopt state left at the pre-#1834 XDG root.
|
|
7973
|
-
*
|
|
7974
|
-
* The daemon used to resolve `$XDG_CONFIG_HOME/moltnet` while the CLI and SDK
|
|
7975
|
-
* resolved `~/.config/moltnet`. Aligning the root without this would silently
|
|
7976
|
-
* orphan an existing daemon's entire state — it would come up reporting zero
|
|
7977
|
-
* managed agents.
|
|
7978
|
-
*/
|
|
7979
|
-
adoptLegacyXdgRoot(xdgConfigHome) {
|
|
7980
|
-
const legacyRoot = legacyXdgAgentServerRoot(xdgConfigHome);
|
|
7981
|
-
if (!legacyRoot || legacyRoot === this.root) return;
|
|
7982
|
-
if (!hasAgentServerState(legacyRoot)) return;
|
|
7983
|
-
if (hasAgentServerState(this.root)) throw new AgentServerStoreError("invalid_state", `agent server state exists at both ${legacyRoot} (the pre-1834 XDG_CONFIG_HOME location) and ${this.root}. The daemon now shares ${this.root} with the CLI and SDK. Merge or remove one of them, or set MOLTNET_AGENT_SERVER_ROOT to choose explicitly.`);
|
|
7984
|
-
mkdirSync(resolve(this.root, ".."), {
|
|
7985
|
-
recursive: true,
|
|
7986
|
-
mode: 448
|
|
7987
|
-
});
|
|
7988
|
-
try {
|
|
7989
|
-
if (readdirSync(this.root).length === 0) rmSync(this.root, { recursive: true });
|
|
7990
|
-
} catch {}
|
|
7991
|
-
try {
|
|
7992
|
-
renameSync(legacyRoot, this.root);
|
|
7993
|
-
} catch (error) {
|
|
7994
|
-
if (error.code !== "EXDEV") throw new AgentServerStoreError("io_error", `could not adopt the pre-1834 agent server state at ${legacyRoot}: ${String(error.message)}. Move it to ${this.root} manually, or set MOLTNET_AGENT_SERVER_ROOT to choose a root explicitly.`);
|
|
7995
|
-
cpSync(legacyRoot, this.root, { recursive: true });
|
|
7996
|
-
rmSync(legacyRoot, {
|
|
7997
|
-
recursive: true,
|
|
7998
|
-
force: true
|
|
7999
|
-
});
|
|
8000
|
-
}
|
|
8001
|
-
}
|
|
8002
|
-
/**
|
|
8003
|
-
* Migrate managed documents from the pre-#1834 `agents/<alias>.json` layout
|
|
8004
|
-
* to `identities/<alias>/moltnet.json`. Without this an upgraded daemon sees
|
|
8005
|
-
* zero managed agents and reports a plain "not found".
|
|
8006
|
-
*/
|
|
8007
|
-
migrateLegacyAgentDocuments() {
|
|
8008
|
-
const legacyDir = join(this.root, "agents");
|
|
8009
|
-
let entries;
|
|
8010
|
-
try {
|
|
8011
|
-
entries = readdirSync(legacyDir);
|
|
8012
|
-
} catch {
|
|
8013
|
-
return;
|
|
8014
|
-
}
|
|
8015
|
-
for (const entry of entries) {
|
|
8016
|
-
if (!entry.endsWith(".json")) continue;
|
|
8017
|
-
const alias = entry.slice(0, -5);
|
|
8018
|
-
if (!NAME_RE.test(alias)) continue;
|
|
8019
|
-
const legacyPath = join(legacyDir, entry);
|
|
8020
|
-
const target = this.agentPath(alias);
|
|
8021
|
-
if (readJson(target)) continue;
|
|
8022
|
-
const config = readJson(legacyPath);
|
|
8023
|
-
if (!config) continue;
|
|
8024
|
-
mkdirSync(join(this.identitiesDir, alias), {
|
|
8025
|
-
recursive: true,
|
|
8026
|
-
mode: 448
|
|
8027
|
-
});
|
|
8028
|
-
writeJsonAtomic(target, config);
|
|
8029
|
-
rmSync(legacyPath, { force: true });
|
|
8030
|
-
}
|
|
8031
|
-
if (readdirSync(legacyDir).length === 0) rmSync(legacyDir, {
|
|
8032
|
-
recursive: true,
|
|
8033
|
-
force: true
|
|
8034
|
-
});
|
|
8035
|
-
}
|
|
8036
7956
|
get statePath() {
|
|
8037
7957
|
return join(this.root, "agent-server.json");
|
|
8038
7958
|
}
|
|
8039
7959
|
readAgentServerState() {
|
|
8040
7960
|
const state = readJson(this.statePath);
|
|
8041
7961
|
if (!state) return {
|
|
8042
|
-
version:
|
|
7962
|
+
version: 2,
|
|
8043
7963
|
pendingRegistrations: {},
|
|
8044
7964
|
activations: {}
|
|
8045
7965
|
};
|
|
8046
|
-
if (!isRecord$1(state) || state.version !==
|
|
8047
|
-
if ("pairedOrigins" in state) throw new AgentServerStoreError("invalid_state", "agent-server.json uses the obsolete pairing format;
|
|
8048
|
-
if (!isRecord$1(state.pendingRegistrations) || !isRecord$1(state.activations)) throw new AgentServerStoreError("invalid_state", "agent-server.json is missing the version
|
|
7966
|
+
if (!isRecord$1(state) || state.version !== 2) throw new AgentServerStoreError("invalid_state", `agent-server.json version ${String(isRecord$1(state) ? state.version : void 0)} is not supported; move agent-server.json aside, run \`moltnet config migrate\`, then add or attach the agents again`);
|
|
7967
|
+
if ("pairedOrigins" in state) throw new AgentServerStoreError("invalid_state", "agent-server.json uses the obsolete pairing format; move agent-server.json aside and configure the agent server again");
|
|
7968
|
+
if (!isRecord$1(state.pendingRegistrations) || !isRecord$1(state.activations)) throw new AgentServerStoreError("invalid_state", "agent-server.json is missing the version 2 activation map; move agent-server.json aside, run `moltnet config migrate`, then add or attach the agents again");
|
|
8049
7969
|
for (const [alias, activation] of Object.entries(state.activations)) validateActivation(alias, activation);
|
|
8050
7970
|
for (const [alias, registration] of Object.entries(state.pendingRegistrations)) {
|
|
8051
7971
|
assertStoreName("agent name", alias);
|
|
8052
7972
|
if (!isRecord$1(registration) || typeof registration.apiUrl !== "string" || registration.apiUrl.length === 0 || typeof registration.createdAt !== "string" || registration.createdAt.length === 0) throw new AgentServerStoreError("invalid_state", `pending registration "${alias}" is not valid`);
|
|
8053
7973
|
}
|
|
8054
7974
|
return {
|
|
8055
|
-
version:
|
|
7975
|
+
version: 2,
|
|
8056
7976
|
pendingRegistrations: state.pendingRegistrations,
|
|
8057
7977
|
activations: state.activations
|
|
8058
7978
|
};
|
|
@@ -8281,13 +8201,13 @@ function isStrictDescendant(root, candidate) {
|
|
|
8281
8201
|
}
|
|
8282
8202
|
function validateActivation(alias, value) {
|
|
8283
8203
|
const invalid = () => {
|
|
8284
|
-
throw new AgentServerStoreError("invalid_state", `activation "${alias}" is not a valid version
|
|
8204
|
+
throw new AgentServerStoreError("invalid_state", `activation "${alias}" is not a valid version 2 activation`);
|
|
8285
8205
|
};
|
|
8286
8206
|
if (!isRecord$1(value)) invalid();
|
|
8287
8207
|
const activation = value;
|
|
8288
8208
|
if (activation.alias !== alias) invalid();
|
|
8289
8209
|
if (![
|
|
8290
|
-
"
|
|
8210
|
+
"subjectId",
|
|
8291
8211
|
"publicKey",
|
|
8292
8212
|
"fingerprint",
|
|
8293
8213
|
"createdAt"
|
|
@@ -8332,7 +8252,7 @@ async function createManagedAgent(store, secrets, input, connectAgent = connect)
|
|
|
8332
8252
|
const alias = assertStoreName("agent name", input.name);
|
|
8333
8253
|
if (!input.enrollmentToken.trim()) throw new AgentServerIdentityError("enrollment_required", "an enrollment token from the target team is required — a self-registered agent would be stranded in its own personal team");
|
|
8334
8254
|
const releaseAlias = reserveAlias(store, alias);
|
|
8335
|
-
let
|
|
8255
|
+
let registered = false;
|
|
8336
8256
|
try {
|
|
8337
8257
|
let apiUrl;
|
|
8338
8258
|
try {
|
|
@@ -8349,18 +8269,19 @@ async function createManagedAgent(store, secrets, input, connectAgent = connect)
|
|
|
8349
8269
|
});
|
|
8350
8270
|
if (result.credentials.type !== "agent_key") throw new AgentServerIdentityError("unsupported_credential", `registration returned credential type "${result.credentials.type}"; agent server manages agent-key credentials only`);
|
|
8351
8271
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8352
|
-
const {
|
|
8353
|
-
|
|
8272
|
+
const { subjectId, fingerprint, publicKey, privateKey } = result.identity;
|
|
8273
|
+
registered = true;
|
|
8354
8274
|
const agentKeyReference = {
|
|
8355
8275
|
provider: FILE_SECRET_PROVIDER,
|
|
8356
|
-
key: agentKeyKey(
|
|
8276
|
+
key: agentKeyKey(subjectId)
|
|
8357
8277
|
};
|
|
8358
8278
|
const seedReference = {
|
|
8359
8279
|
provider: FILE_SECRET_PROVIDER,
|
|
8360
8280
|
key: identitySeedKey(fingerprint)
|
|
8361
8281
|
};
|
|
8362
8282
|
const config = {
|
|
8363
|
-
|
|
8283
|
+
subject_id: subjectId,
|
|
8284
|
+
subject_type: "agent",
|
|
8364
8285
|
registered_at: now,
|
|
8365
8286
|
agent_key_ref: agentKeyReference,
|
|
8366
8287
|
keys: {
|
|
@@ -8381,15 +8302,15 @@ async function createManagedAgent(store, secrets, input, connectAgent = connect)
|
|
|
8381
8302
|
apiUrl: result.apiUrl
|
|
8382
8303
|
}, store.agentPath(alias), input.signal);
|
|
8383
8304
|
assertIdentityMatches(whoami, {
|
|
8384
|
-
identityId,
|
|
8385
8305
|
publicKey,
|
|
8386
8306
|
fingerprint
|
|
8387
8307
|
}, "authenticated whoami", `new managed agent "${alias}"`);
|
|
8308
|
+
assertSubjectMatches(whoami, config, "authenticated whoami", `managed config ${store.agentPath(alias)}`);
|
|
8388
8309
|
const boundTeamId = boundTeamIdFromWhoami(whoami);
|
|
8389
8310
|
const activation = {
|
|
8390
8311
|
alias,
|
|
8391
8312
|
source: "managed",
|
|
8392
|
-
|
|
8313
|
+
subjectId: whoami.subjectId,
|
|
8393
8314
|
publicKey,
|
|
8394
8315
|
fingerprint,
|
|
8395
8316
|
...boundTeamId ? { boundTeamId } : {},
|
|
@@ -8403,11 +8324,11 @@ async function createManagedAgent(store, secrets, input, connectAgent = connect)
|
|
|
8403
8324
|
...boundTeamId ? { boundTeamId } : {}
|
|
8404
8325
|
};
|
|
8405
8326
|
} catch (cause) {
|
|
8406
|
-
if (!
|
|
8327
|
+
if (!registered && cause instanceof MoltNetError && cause.statusCode !== void 0 && cause.statusCode >= 400 && cause.statusCode < 500) {
|
|
8407
8328
|
store.clearPendingRegistration(alias);
|
|
8408
8329
|
throw new AgentServerIdentityError("registration_failed", registrationRejectionMessage(alias, cause), { cause });
|
|
8409
8330
|
}
|
|
8410
|
-
if (store.hasPendingRegistration(alias)) throw new AgentServerIdentityError("registration_incomplete",
|
|
8331
|
+
if (store.hasPendingRegistration(alias)) throw new AgentServerIdentityError("registration_incomplete", registered ? `the remote agent was registered but local activation is incomplete; reconcile or clear its pending Agent Server record before retrying` : `registration for "${alias}" may be incomplete; inspect the remote API before changing its pending Agent Server record`, { cause });
|
|
8411
8332
|
throw cause;
|
|
8412
8333
|
} finally {
|
|
8413
8334
|
releaseAlias();
|
|
@@ -8438,17 +8359,19 @@ async function reconcileManagedRegistration(store, secrets, aliasInput, action,
|
|
|
8438
8359
|
if (!config?.agent_key_ref || config.agent_key_ref.provider !== FILE_SECRET_PROVIDER || config.keys.private_key_ref?.provider !== FILE_SECRET_PROVIDER) throw new AgentServerIdentityError("registration_incomplete", `pending registration for "${alias}" does not have complete managed references`);
|
|
8439
8360
|
const [agentKey, privateKeyState] = await Promise.all([secrets.read(config.agent_key_ref.key), secrets.probe(config.keys.private_key_ref.key)]);
|
|
8440
8361
|
if (!agentKey || privateKeyState !== "present") throw new AgentServerIdentityError("registration_incomplete", `pending registration for "${alias}" is missing persisted secret material`);
|
|
8441
|
-
const identity = identityFromConfig(config);
|
|
8442
8362
|
const apiUrl = requireConfigApiUrl(config, store.agentPath(alias));
|
|
8443
8363
|
const whoami = await callWhoami(connectAgent, {
|
|
8444
8364
|
agentKey,
|
|
8445
8365
|
apiUrl
|
|
8446
8366
|
}, store.agentPath(alias), signal);
|
|
8367
|
+
assertSubjectMatches(whoami, config, "authenticated whoami", `pending registration "${alias}" config`);
|
|
8368
|
+
const identity = identityFromConfig(config);
|
|
8447
8369
|
assertIdentityMatches(whoami, identity, "authenticated whoami", `pending registration "${alias}" config`);
|
|
8448
8370
|
const boundTeamId = boundTeamIdFromWhoami(whoami);
|
|
8449
8371
|
const recovered = {
|
|
8450
8372
|
alias,
|
|
8451
8373
|
source: "managed",
|
|
8374
|
+
subjectId: whoami.subjectId,
|
|
8452
8375
|
...identity,
|
|
8453
8376
|
...boundTeamId ? { boundTeamId } : {},
|
|
8454
8377
|
createdAt: config.registered_at,
|
|
@@ -8470,14 +8393,15 @@ async function attachExternalAgent(store, secretProviders, input, connectAgent =
|
|
|
8470
8393
|
externalAgentLocation(configPath);
|
|
8471
8394
|
const config = await readCurrentConfig(configPath);
|
|
8472
8395
|
const configApiUrl = requireTrustedConfigApiUrl(config, configPath);
|
|
8473
|
-
const
|
|
8474
|
-
const whoami = await authenticateConfig(input.configDir, effectiveApiUrl, secretProviders, connectAgent, input.signal);
|
|
8396
|
+
const whoami = await authenticateConfig(config, configPath, requireTrustedApiOverride(input.apiUrl, configApiUrl, configPath), secretProviders, connectAgent, input.signal);
|
|
8475
8397
|
const identity = identityFromConfig(config);
|
|
8476
8398
|
assertIdentityMatches(identity, whoami, `external config ${configPath}`, "authenticated whoami");
|
|
8399
|
+
assertSubjectMatches(whoami, config, "authenticated whoami", `external config ${configPath}`);
|
|
8477
8400
|
const boundTeamId = boundTeamIdFromWhoami(whoami);
|
|
8478
8401
|
const activation = {
|
|
8479
8402
|
alias,
|
|
8480
8403
|
source: "external",
|
|
8404
|
+
subjectId: whoami.subjectId,
|
|
8481
8405
|
...identity,
|
|
8482
8406
|
...boundTeamId ? { boundTeamId } : {},
|
|
8483
8407
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -8495,15 +8419,26 @@ async function attachExternalAgent(store, secretProviders, input, connectAgent =
|
|
|
8495
8419
|
releaseAlias();
|
|
8496
8420
|
}
|
|
8497
8421
|
}
|
|
8498
|
-
/** Load and authenticate the current config, then
|
|
8422
|
+
/** Load and authenticate the current config, then refresh its derived pin. */
|
|
8499
8423
|
async function verifyAgentActivation(store, alias, managedSecretProviders, externalSecretProviders, connectAgent = connect, signal) {
|
|
8500
8424
|
const activation = requireActivation(store, alias);
|
|
8501
8425
|
const verified = activation.source === "managed" ? await verifyManagedActivation(store, activation, managedSecretProviders, connectAgent, signal) : await verifyExternalActivation(activation, externalSecretProviders, connectAgent, signal);
|
|
8502
|
-
|
|
8426
|
+
assertSubjectMatches(verified.whoami, verified.config, "authenticated whoami", `agent "${activation.alias}" config`);
|
|
8427
|
+
if (verified.whoami.subjectId !== activation.subjectId) throw new AgentServerIdentityError("verification_failed", `authenticated whoami subject does not match agent "${activation.alias}" pinned activation`);
|
|
8428
|
+
const identity = identityFromConfig(verified.config);
|
|
8429
|
+
assertIdentityMatches(verified.whoami, identity, "authenticated whoami", `agent "${activation.alias}" config`);
|
|
8503
8430
|
const boundTeamId = boundTeamIdFromWhoami(verified.whoami);
|
|
8504
8431
|
if (activation.boundTeamId !== boundTeamId) throw new AgentServerIdentityError("verification_failed", `authenticated whoami team binding does not match agent "${activation.alias}" pinned activation`);
|
|
8432
|
+
const refreshed = {
|
|
8433
|
+
...activation,
|
|
8434
|
+
...identity
|
|
8435
|
+
};
|
|
8436
|
+
if (activation.publicKey !== refreshed.publicKey || activation.fingerprint !== refreshed.fingerprint) {
|
|
8437
|
+
store.writeActivation(refreshed);
|
|
8438
|
+
process.stderr.write(`agent-server: refreshed the authenticated signing identity for ${JSON.stringify(activation.alias)}\n`);
|
|
8439
|
+
}
|
|
8505
8440
|
return {
|
|
8506
|
-
activation,
|
|
8441
|
+
activation: refreshed,
|
|
8507
8442
|
config: verified.config,
|
|
8508
8443
|
...boundTeamId ? { boundTeamId } : {}
|
|
8509
8444
|
};
|
|
@@ -8535,7 +8470,7 @@ async function verifyExternalActivation(activation, secretProviders, connectAgen
|
|
|
8535
8470
|
const effectiveApiUrl = requireTrustedApiOverride(activation.apiUrl, activation.configApiUrl, activation.configPath);
|
|
8536
8471
|
return {
|
|
8537
8472
|
config,
|
|
8538
|
-
whoami: await authenticateConfig(
|
|
8473
|
+
whoami: await authenticateConfig(config, activation.configPath, effectiveApiUrl, secretProviders, connectAgent, signal)
|
|
8539
8474
|
};
|
|
8540
8475
|
}
|
|
8541
8476
|
/** Never let request or activation metadata redirect persisted credentials. */
|
|
@@ -8546,7 +8481,7 @@ function requireTrustedApiOverride(override, configApiUrl, configPath) {
|
|
|
8546
8481
|
}
|
|
8547
8482
|
function assertActivatedConfig(config, activation, configPath, currentApiUrl, pinnedApiUrl) {
|
|
8548
8483
|
if (currentApiUrl !== pinnedApiUrl) throw new AgentServerIdentityError("verification_failed", `agent config at ${configPath} API endpoint does not match its pinned activation`);
|
|
8549
|
-
|
|
8484
|
+
if (config.subject_id !== activation.subjectId) throw new AgentServerIdentityError("verification_failed", `agent config at ${configPath} subject does not match its pinned activation`);
|
|
8550
8485
|
}
|
|
8551
8486
|
function requireConfigApiUrl(config, configPath) {
|
|
8552
8487
|
const apiUrl = config?.endpoints?.api?.trim();
|
|
@@ -8595,12 +8530,18 @@ function externalAgentLocation(configPath) {
|
|
|
8595
8530
|
agentRoot: dirname(moltnetDir)
|
|
8596
8531
|
};
|
|
8597
8532
|
}
|
|
8598
|
-
async function authenticateConfig(
|
|
8533
|
+
async function authenticateConfig(config, configPath, apiUrl, secretProviders, connectAgent, signal) {
|
|
8534
|
+
let agentKey;
|
|
8535
|
+
try {
|
|
8536
|
+
agentKey = await resolveAgentKey(config, secretProviders);
|
|
8537
|
+
} catch (cause) {
|
|
8538
|
+
throw verificationError(`could not resolve the daemon agent key from ${configPath}`, cause);
|
|
8539
|
+
}
|
|
8540
|
+
if (!agentKey) throw new AgentServerIdentityError("unsupported_credential", `external daemon config at ${configPath} must contain an agent_key_ref`);
|
|
8599
8541
|
return callWhoami(connectAgent, {
|
|
8600
|
-
|
|
8601
|
-
...apiUrl ? { apiUrl } : {}
|
|
8602
|
-
|
|
8603
|
-
}, configDir, signal);
|
|
8542
|
+
agentKey,
|
|
8543
|
+
...apiUrl ? { apiUrl } : {}
|
|
8544
|
+
}, configPath, signal);
|
|
8604
8545
|
}
|
|
8605
8546
|
async function callWhoami(connectAgent, options, source, signal) {
|
|
8606
8547
|
try {
|
|
@@ -8618,16 +8559,18 @@ function boundedIdentitySignal(signal) {
|
|
|
8618
8559
|
return signal ? AbortSignal.any([signal, timeout]) : timeout;
|
|
8619
8560
|
}
|
|
8620
8561
|
function identityFromConfig(config) {
|
|
8621
|
-
const identityId = config?.identity_id?.trim();
|
|
8622
8562
|
const publicKey = config?.keys?.public_key?.trim();
|
|
8623
8563
|
const fingerprint = config?.keys?.fingerprint?.trim();
|
|
8624
|
-
if (!
|
|
8564
|
+
if (!publicKey || !fingerprint) throw new AgentServerIdentityError("verification_failed", "agent config is missing keys.public_key or keys.fingerprint");
|
|
8625
8565
|
return {
|
|
8626
|
-
identityId,
|
|
8627
8566
|
publicKey,
|
|
8628
8567
|
fingerprint
|
|
8629
8568
|
};
|
|
8630
8569
|
}
|
|
8570
|
+
function assertSubjectMatches(current, expected, currentLabel, expectedLabel) {
|
|
8571
|
+
if (!isCanonicalConfig(expected)) throw new AgentServerIdentityError("verification_failed", `${expectedLabel} is missing canonical subject_type=agent and subject_id; run \`moltnet config migrate\` first`);
|
|
8572
|
+
if (current.subjectType !== "agent" || current.subjectId !== expected.subject_id) throw new AgentServerIdentityError("verification_failed", `${currentLabel} subject does not match ${expectedLabel}`);
|
|
8573
|
+
}
|
|
8631
8574
|
function assertIdentityMatches(current, expected, currentLabel, expectedLabel) {
|
|
8632
8575
|
const assessment = assessIdentityPin(current, expected);
|
|
8633
8576
|
if (!assessment.ok) throw new AgentServerIdentityError("verification_failed", `${currentLabel} ${assessment.label} does not match ${expectedLabel}`);
|
|
@@ -8642,7 +8585,7 @@ function publicAgentView(store, activation) {
|
|
|
8642
8585
|
return {
|
|
8643
8586
|
kind: "managed",
|
|
8644
8587
|
agentName: activation.alias,
|
|
8645
|
-
|
|
8588
|
+
subjectId: activation.subjectId,
|
|
8646
8589
|
fingerprint: activation.fingerprint,
|
|
8647
8590
|
...activation.boundTeamId ? { teamId: activation.boundTeamId } : {},
|
|
8648
8591
|
apiUrl: activation.apiUrl,
|
|
@@ -8656,7 +8599,7 @@ function publicAgentView(store, activation) {
|
|
|
8656
8599
|
agentName: activation.alias,
|
|
8657
8600
|
configDir: dirname(activation.configPath),
|
|
8658
8601
|
...activation.apiUrl ? { apiUrl: activation.apiUrl } : {},
|
|
8659
|
-
|
|
8602
|
+
subjectId: activation.subjectId,
|
|
8660
8603
|
fingerprint: activation.fingerprint,
|
|
8661
8604
|
...activation.boundTeamId ? { teamId: activation.boundTeamId } : {},
|
|
8662
8605
|
createdAt: activation.createdAt
|
|
@@ -8790,19 +8733,15 @@ var RunManager = class {
|
|
|
8790
8733
|
env["MOLTNET_API_URL"] = activation.apiUrl ?? activation.configApiUrl;
|
|
8791
8734
|
try {
|
|
8792
8735
|
const agentKey = await resolveAgentKey(config, this.options.externalSecretProviders);
|
|
8793
|
-
if (agentKey)
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
} else if (config.oauth2?.client_secret_ref) {
|
|
8797
|
-
env["MOLTNET_CLIENT_ID"] = config.oauth2.client_id;
|
|
8798
|
-
env["MOLTNET_CLIENT_SECRET"] = await resolveOAuth2ClientSecret(config, this.options.externalSecretProviders);
|
|
8799
|
-
}
|
|
8800
|
-
if (!agentKey && config.keys.private_key_ref) env["MOLTNET_PRIVATE_KEY"] = await resolveIdentitySeed(config, this.options.externalSecretProviders);
|
|
8736
|
+
if (!agentKey) throw new Error("external daemon config has no agent key");
|
|
8737
|
+
env["MOLTNET_AGENT_KEY"] = agentKey;
|
|
8738
|
+
env["MOLTNET_PRIVATE_KEY"] = await resolveIdentitySeed(config, this.options.externalSecretProviders);
|
|
8801
8739
|
} catch {
|
|
8802
8740
|
throw new AgentServerRunError("invalid_spec", `external credentials for "${activation.alias}" could not be projected`);
|
|
8803
8741
|
}
|
|
8804
8742
|
}
|
|
8805
|
-
env["
|
|
8743
|
+
env["MOLTNET_EXPECTED_SUBJECT_ID"] = activation.subjectId;
|
|
8744
|
+
env["MOLTNET_EXPECTED_SUBJECT_TYPE"] = "agent";
|
|
8806
8745
|
env["MOLTNET_EXPECTED_PUBLIC_KEY"] = activation.publicKey;
|
|
8807
8746
|
env["MOLTNET_EXPECTED_FINGERPRINT"] = activation.fingerprint;
|
|
8808
8747
|
env["MOLTNET_SUPERVISED_RUN"] = "1";
|
|
@@ -9006,10 +8945,11 @@ var RunManager = class {
|
|
|
9006
8945
|
apiUrl: activation.apiUrl
|
|
9007
8946
|
});
|
|
9008
8947
|
}
|
|
8948
|
+
const agentKey = await resolveAgentKey(config, this.options.externalSecretProviders);
|
|
8949
|
+
if (!agentKey) throw new AgentServerRunError("invalid_spec", `external agent "${activation.alias}" has no agent key`);
|
|
9009
8950
|
return connect({
|
|
9010
|
-
|
|
9011
|
-
apiUrl: activation.apiUrl ?? activation.configApiUrl
|
|
9012
|
-
secretProviders: this.options.externalSecretProviders
|
|
8951
|
+
agentKey,
|
|
8952
|
+
apiUrl: activation.apiUrl ?? activation.configApiUrl
|
|
9013
8953
|
});
|
|
9014
8954
|
}
|
|
9015
8955
|
stop(id) {
|
|
@@ -9459,7 +9399,7 @@ var AgentServerProblemSchema = Type.Object({
|
|
|
9459
9399
|
var AgentServerAgentSchema = Type.Object({
|
|
9460
9400
|
kind: Type.Union([Type.Literal("managed"), Type.Literal("external")]),
|
|
9461
9401
|
agentName: Type.String(),
|
|
9462
|
-
|
|
9402
|
+
subjectId: Type.String(),
|
|
9463
9403
|
fingerprint: Type.Optional(Type.String()),
|
|
9464
9404
|
apiUrl: Type.Optional(Type.String()),
|
|
9465
9405
|
teamId: Type.Optional(Type.String()),
|
|
@@ -10624,7 +10564,7 @@ async function runAgentServer(argv) {
|
|
|
10624
10564
|
const allowedOrigins = parseAllowedOrigins(values["allowed-origins"] ?? (envConfig.allowedOrigins || DEFAULT_ALLOWED_ORIGINS));
|
|
10625
10565
|
const root = values.root ?? resolveAgentServerRoot({ root: envConfig.root });
|
|
10626
10566
|
const defaultApiUrl = values["api-url"] ?? (envConfig.apiUrl || DEFAULT_API_URL);
|
|
10627
|
-
const store = new AgentServerStore(root).ensure(
|
|
10567
|
+
const store = new AgentServerStore(root).ensure();
|
|
10628
10568
|
if (trustRequested) return runTrustCommand(commandArgs, root);
|
|
10629
10569
|
const { logger, shutdown: shutdownLogger } = createRootLogger({
|
|
10630
10570
|
name: "agent-daemon.server",
|
|
@@ -11112,7 +11052,7 @@ async function writeCache(cache) {
|
|
|
11112
11052
|
}
|
|
11113
11053
|
//#endregion
|
|
11114
11054
|
//#region src/version.ts
|
|
11115
|
-
var DAEMON_VERSION = "0.
|
|
11055
|
+
var DAEMON_VERSION = "0.55.1";
|
|
11116
11056
|
//#endregion
|
|
11117
11057
|
//#region src/cli.ts
|
|
11118
11058
|
async function runAgentDaemonCli(options) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@themoltnet/agent-daemon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.55.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.",
|
|
@@ -85,10 +85,10 @@
|
|
|
85
85
|
"proper-lockfile": "4.1.2",
|
|
86
86
|
"reflect-metadata": "^0.2.2",
|
|
87
87
|
"typebox": "^1.2.8",
|
|
88
|
-
"@themoltnet/
|
|
89
|
-
"@themoltnet/
|
|
90
|
-
"@themoltnet/
|
|
91
|
-
"@themoltnet/
|
|
88
|
+
"@themoltnet/agent-runtime": "1.0.1",
|
|
89
|
+
"@themoltnet/os-keyring": "0.3.0",
|
|
90
|
+
"@themoltnet/pi-runtime": "0.15.1",
|
|
91
|
+
"@themoltnet/sdk": "0.141.1"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
94
|
"@fastify/swagger": "^9.6.1",
|
|
@@ -99,15 +99,15 @@
|
|
|
99
99
|
"vite-plugin-dts": "^4.5.4",
|
|
100
100
|
"vitest": "^3.0.0",
|
|
101
101
|
"@moltnet/bootstrap": "0.1.0",
|
|
102
|
+
"@moltnet/agent-eval": "0.1.0",
|
|
102
103
|
"@moltnet/crypto-service": "0.1.0",
|
|
103
104
|
"@moltnet/execution-plan": "0.1.0",
|
|
104
105
|
"@moltnet/execution-integrations": "0.1.0",
|
|
105
|
-
"@moltnet/runtime-profiles": "0.1.0",
|
|
106
|
-
"@moltnet/tasks": "0.1.0",
|
|
107
106
|
"@moltnet/loopback-companion": "0.1.0",
|
|
108
|
-
"@moltnet/
|
|
107
|
+
"@moltnet/models": "0.1.0",
|
|
109
108
|
"@moltnet/observability": "0.1.0",
|
|
110
|
-
"@moltnet/
|
|
109
|
+
"@moltnet/runtime-profiles": "0.1.0",
|
|
110
|
+
"@moltnet/tasks": "0.1.0"
|
|
111
111
|
},
|
|
112
112
|
"nx": {
|
|
113
113
|
"projectType": "application",
|