@themoltnet/pi-extension 0.35.2 → 0.35.4

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.
Files changed (2) hide show
  1. package/dist/index.js +448 -79
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -42,6 +42,59 @@ var __copyProps = (to, from, except, desc) => {
42
42
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
43
43
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
44
44
  //#endregion
45
+ //#region ../sdk/src/errors.ts
46
+ var MoltNetError = class extends Error {
47
+ code;
48
+ statusCode;
49
+ detail;
50
+ /**
51
+ * Populated when the server returned a `VALIDATION_FAILED` problem
52
+ * (status 400) with field-level errors. Empty / undefined for every
53
+ * other problem kind. Proposer scripts surface these to operators so
54
+ * they don't have to re-run with curl to see what was rejected.
55
+ */
56
+ validationErrors;
57
+ constructor(message, options) {
58
+ super(message);
59
+ this.name = "MoltNetError";
60
+ this.code = options.code;
61
+ this.statusCode = options.statusCode;
62
+ this.detail = options.detail;
63
+ this.validationErrors = options.validationErrors;
64
+ }
65
+ };
66
+ var NetworkError = class extends MoltNetError {
67
+ constructor(message, options) {
68
+ super(message, {
69
+ code: "NETWORK_ERROR",
70
+ detail: options?.detail
71
+ });
72
+ this.name = "NetworkError";
73
+ }
74
+ };
75
+ var AuthenticationError = class extends MoltNetError {
76
+ constructor(message, options) {
77
+ super(message, {
78
+ code: "AUTH_FAILED",
79
+ statusCode: options?.statusCode,
80
+ detail: options?.detail
81
+ });
82
+ this.name = "AuthenticationError";
83
+ }
84
+ };
85
+ function problemToError(problem, statusCode) {
86
+ const title = problem.title ?? "Request failed";
87
+ const message = problem.detail ? `${title}: ${problem.detail}` : title;
88
+ const rawErrors = problem.errors;
89
+ const validationErrors = Array.isArray(rawErrors) ? rawErrors.filter((e) => typeof e === "object" && e !== null && typeof e.field === "string" && typeof e.message === "string") : void 0;
90
+ return new MoltNetError(message, {
91
+ code: problem.type ?? problem.code ?? "UNKNOWN",
92
+ statusCode,
93
+ detail: problem.detail,
94
+ validationErrors
95
+ });
96
+ }
97
+ //#endregion
45
98
  //#region ../api-client/src/generated/core/bodySerializer.gen.ts
46
99
  var jsonBodySerializer = { bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value) };
47
100
  Object.entries({
@@ -754,7 +807,7 @@ var rotateAgentKey = (options) => (options.client ?? client).post({
754
807
  ...options
755
808
  });
756
809
  /**
757
- * Get the authenticated agent identity (requires bearer token).
810
+ * Get the authenticated caller identity and context. Works for both agents (identity plus, under agent-key auth, the credential binding) and humans, via bearer, session, or cookie auth.
758
811
  */
759
812
  var getWhoami = (options) => (options?.client ?? client).get({
760
813
  security: [
@@ -837,6 +890,145 @@ var getCryptoIdentity = (options) => (options?.client ?? client).get({
837
890
  url: "/crypto/identity",
838
891
  ...options
839
892
  });
893
+ var listSigningCredentials = (options) => (options.client ?? client).get({
894
+ security: [
895
+ {
896
+ scheme: "bearer",
897
+ type: "http"
898
+ },
899
+ {
900
+ name: "X-Moltnet-Session-Token",
901
+ type: "apiKey"
902
+ },
903
+ {
904
+ in: "cookie",
905
+ name: "ory_kratos_session",
906
+ type: "apiKey"
907
+ }
908
+ ],
909
+ url: "/crypto/signing-credentials",
910
+ ...options
911
+ });
912
+ var beginSigningCredentialRegistration = (options) => (options.client ?? client).post({
913
+ security: [{
914
+ name: "X-Moltnet-Session-Token",
915
+ type: "apiKey"
916
+ }, {
917
+ in: "cookie",
918
+ name: "ory_kratos_session",
919
+ type: "apiKey"
920
+ }],
921
+ url: "/crypto/signing-credentials/registrations",
922
+ ...options,
923
+ headers: {
924
+ "Content-Type": "application/json",
925
+ ...options.headers
926
+ }
927
+ });
928
+ var completeSigningCredentialRegistration = (options) => (options.client ?? client).post({
929
+ security: [{
930
+ name: "X-Moltnet-Session-Token",
931
+ type: "apiKey"
932
+ }, {
933
+ in: "cookie",
934
+ name: "ory_kratos_session",
935
+ type: "apiKey"
936
+ }],
937
+ url: "/crypto/signing-credentials/registrations/{id}/complete",
938
+ ...options,
939
+ headers: {
940
+ "Content-Type": "application/json",
941
+ ...options.headers
942
+ }
943
+ });
944
+ var getSigningCredential = (options) => (options.client ?? client).get({
945
+ security: [
946
+ {
947
+ scheme: "bearer",
948
+ type: "http"
949
+ },
950
+ {
951
+ name: "X-Moltnet-Session-Token",
952
+ type: "apiKey"
953
+ },
954
+ {
955
+ in: "cookie",
956
+ name: "ory_kratos_session",
957
+ type: "apiKey"
958
+ }
959
+ ],
960
+ url: "/crypto/signing-credentials/{id}",
961
+ ...options
962
+ });
963
+ var approveSigningCredential = (options) => (options.client ?? client).post({
964
+ security: [
965
+ {
966
+ scheme: "bearer",
967
+ type: "http"
968
+ },
969
+ {
970
+ name: "X-Moltnet-Session-Token",
971
+ type: "apiKey"
972
+ },
973
+ {
974
+ in: "cookie",
975
+ name: "ory_kratos_session",
976
+ type: "apiKey"
977
+ }
978
+ ],
979
+ url: "/crypto/signing-credentials/{id}/approve",
980
+ ...options,
981
+ headers: {
982
+ "Content-Type": "application/json",
983
+ ...options.headers
984
+ }
985
+ });
986
+ var revokeSigningCredential = (options) => (options.client ?? client).post({
987
+ security: [
988
+ {
989
+ scheme: "bearer",
990
+ type: "http"
991
+ },
992
+ {
993
+ name: "X-Moltnet-Session-Token",
994
+ type: "apiKey"
995
+ },
996
+ {
997
+ in: "cookie",
998
+ name: "ory_kratos_session",
999
+ type: "apiKey"
1000
+ }
1001
+ ],
1002
+ url: "/crypto/signing-credentials/{id}/revoke",
1003
+ ...options,
1004
+ headers: {
1005
+ "Content-Type": "application/json",
1006
+ ...options.headers
1007
+ }
1008
+ });
1009
+ var suspendSigningCredential = (options) => (options.client ?? client).post({
1010
+ security: [
1011
+ {
1012
+ scheme: "bearer",
1013
+ type: "http"
1014
+ },
1015
+ {
1016
+ name: "X-Moltnet-Session-Token",
1017
+ type: "apiKey"
1018
+ },
1019
+ {
1020
+ in: "cookie",
1021
+ name: "ory_kratos_session",
1022
+ type: "apiKey"
1023
+ }
1024
+ ],
1025
+ url: "/crypto/signing-credentials/{id}/suspend",
1026
+ ...options,
1027
+ headers: {
1028
+ "Content-Type": "application/json",
1029
+ ...options.headers
1030
+ }
1031
+ });
840
1032
  /**
841
1033
  * List signing requests for the authenticated agent.
842
1034
  */
@@ -907,6 +1099,54 @@ var getSigningRequest = (options) => (options.client ?? client).get({
907
1099
  url: "/crypto/signing-requests/{id}",
908
1100
  ...options
909
1101
  });
1102
+ var claimSigningRequest = (options) => (options.client ?? client).post({
1103
+ security: [{
1104
+ name: "X-Moltnet-Session-Token",
1105
+ type: "apiKey"
1106
+ }, {
1107
+ in: "cookie",
1108
+ name: "ory_kratos_session",
1109
+ type: "apiKey"
1110
+ }],
1111
+ url: "/crypto/signing-requests/{id}/claim",
1112
+ ...options,
1113
+ headers: {
1114
+ "Content-Type": "application/json",
1115
+ ...options.headers
1116
+ }
1117
+ });
1118
+ var completeSigningRequest = (options) => (options.client ?? client).post({
1119
+ security: [{
1120
+ name: "X-Moltnet-Session-Token",
1121
+ type: "apiKey"
1122
+ }, {
1123
+ in: "cookie",
1124
+ name: "ory_kratos_session",
1125
+ type: "apiKey"
1126
+ }],
1127
+ url: "/crypto/signing-requests/{id}/complete",
1128
+ ...options,
1129
+ headers: {
1130
+ "Content-Type": "application/json",
1131
+ ...options.headers
1132
+ }
1133
+ });
1134
+ var rejectSigningRequest = (options) => (options.client ?? client).post({
1135
+ security: [{
1136
+ name: "X-Moltnet-Session-Token",
1137
+ type: "apiKey"
1138
+ }, {
1139
+ in: "cookie",
1140
+ name: "ory_kratos_session",
1141
+ type: "apiKey"
1142
+ }],
1143
+ url: "/crypto/signing-requests/{id}/reject",
1144
+ ...options,
1145
+ headers: {
1146
+ "Content-Type": "application/json",
1147
+ ...options.headers
1148
+ }
1149
+ });
910
1150
  /**
911
1151
  * Submit a signature for a signing request. The DBOS workflow verifies the signature and updates the request status.
912
1152
  */
@@ -2934,63 +3174,11 @@ function createRateLimitFetch(options) {
2934
3174
  });
2935
3175
  }
2936
3176
  //#endregion
2937
- //#region ../sdk/src/errors.ts
2938
- var MoltNetError = class extends Error {
2939
- code;
2940
- statusCode;
2941
- detail;
2942
- /**
2943
- * Populated when the server returned a `VALIDATION_FAILED` problem
2944
- * (status 400) with field-level errors. Empty / undefined for every
2945
- * other problem kind. Proposer scripts surface these to operators so
2946
- * they don't have to re-run with curl to see what was rejected.
2947
- */
2948
- validationErrors;
2949
- constructor(message, options) {
2950
- super(message);
2951
- this.name = "MoltNetError";
2952
- this.code = options.code;
2953
- this.statusCode = options.statusCode;
2954
- this.detail = options.detail;
2955
- this.validationErrors = options.validationErrors;
2956
- }
2957
- };
2958
- var NetworkError = class extends MoltNetError {
2959
- constructor(message, options) {
2960
- super(message, {
2961
- code: "NETWORK_ERROR",
2962
- detail: options?.detail
2963
- });
2964
- this.name = "NetworkError";
2965
- }
2966
- };
2967
- var AuthenticationError = class extends MoltNetError {
2968
- constructor(message, options) {
2969
- super(message, {
2970
- code: "AUTH_FAILED",
2971
- statusCode: options?.statusCode,
2972
- detail: options?.detail
2973
- });
2974
- this.name = "AuthenticationError";
2975
- }
2976
- };
2977
- function problemToError(problem, statusCode) {
2978
- const title = problem.title ?? "Request failed";
2979
- const message = problem.detail ? `${title}: ${problem.detail}` : title;
2980
- const rawErrors = problem.errors;
2981
- const validationErrors = Array.isArray(rawErrors) ? rawErrors.filter((e) => typeof e === "object" && e !== null && typeof e.field === "string" && typeof e.message === "string") : void 0;
2982
- return new MoltNetError(message, {
2983
- code: problem.type ?? problem.code ?? "UNKNOWN",
2984
- statusCode,
2985
- detail: problem.detail,
2986
- validationErrors
2987
- });
2988
- }
2989
- //#endregion
2990
3177
  //#region ../sdk/src/agent-context.ts
2991
3178
  function unwrapResult(result) {
2992
3179
  if (result.error !== void 0 && result.error !== null) {
2993
3180
  const error = result.error;
3181
+ if (error instanceof MoltNetError) throw error;
2994
3182
  if (isProblemDetails(error)) throw problemToError(error, error.status);
2995
3183
  if (error instanceof Error && result.response === void 0) {
2996
3184
  const networkError = new NetworkError(error.message, { detail: error.cause ? stringifyUnknown(error.cause) : void 0 });
@@ -3113,16 +3301,25 @@ function createAgentKeysNamespace(context) {
3113
3301
  };
3114
3302
  }
3115
3303
  //#endregion
3304
+ //#region ../sdk/src/namespaces/whoami.ts
3305
+ /**
3306
+ * Build a `whoami()` accessor bound to an authenticated context. Returns the
3307
+ * caller's identity and context: `subjectType`, `currentTeamId`, and, for an
3308
+ * agent authenticated via an agent key, its `credentialBinding`.
3309
+ */
3310
+ function createWhoami(context) {
3311
+ const { client, auth } = context;
3312
+ return async () => unwrapResult(await getWhoami({
3313
+ client,
3314
+ auth
3315
+ }));
3316
+ }
3317
+ //#endregion
3116
3318
  //#region ../sdk/src/namespaces/agents.ts
3117
3319
  function createAgentsNamespace(context) {
3118
- const { client, auth } = context;
3320
+ const { client } = context;
3119
3321
  return {
3120
- async whoami() {
3121
- return unwrapResult(await getWhoami({
3122
- client,
3123
- auth
3124
- }));
3125
- },
3322
+ whoami: createWhoami(context),
3126
3323
  async lookup(fingerprint) {
3127
3324
  return unwrapResult(await getAgentProfile({
3128
3325
  client,
@@ -3151,7 +3348,7 @@ function createAuthNamespace(context) {
3151
3348
  }
3152
3349
  //#endregion
3153
3350
  //#region ../sdk/src/namespaces/crypto.ts
3154
- function createCryptoNamespace(context, signingRequests) {
3351
+ function createCryptoNamespace(context, signingRequests, signingCredentials) {
3155
3352
  const { client, auth } = context;
3156
3353
  return {
3157
3354
  async identity() {
@@ -3166,7 +3363,8 @@ function createCryptoNamespace(context, signingRequests) {
3166
3363
  body
3167
3364
  }));
3168
3365
  },
3169
- signingRequests
3366
+ signingRequests,
3367
+ signingCredentials
3170
3368
  };
3171
3369
  }
3172
3370
  //#endregion
@@ -5458,6 +5656,70 @@ function createRuntimeSlotsNamespace(context) {
5458
5656
  };
5459
5657
  }
5460
5658
  //#endregion
5659
+ //#region ../sdk/src/namespaces/signing-credentials.ts
5660
+ function createSigningCredentialsNamespace(context) {
5661
+ const { client, auth } = context;
5662
+ return {
5663
+ async list(query, options) {
5664
+ return unwrapResult(await listSigningCredentials({
5665
+ client,
5666
+ auth,
5667
+ headers: requiredTeamHeaders(options),
5668
+ query
5669
+ }));
5670
+ },
5671
+ async get(id, options) {
5672
+ return unwrapResult(await getSigningCredential({
5673
+ client,
5674
+ auth,
5675
+ headers: requiredTeamHeaders(options),
5676
+ path: { id }
5677
+ }));
5678
+ },
5679
+ async startRegistration(body, options) {
5680
+ return unwrapResult(await beginSigningCredentialRegistration({
5681
+ client,
5682
+ auth,
5683
+ headers: requiredTeamHeaders(options),
5684
+ body
5685
+ }));
5686
+ },
5687
+ async completeRegistration(id, body, options) {
5688
+ return unwrapResult(await completeSigningCredentialRegistration({
5689
+ client,
5690
+ auth,
5691
+ headers: requiredTeamHeaders(options),
5692
+ path: { id },
5693
+ body
5694
+ }));
5695
+ },
5696
+ async approve(id, options) {
5697
+ return unwrapResult(await approveSigningCredential({
5698
+ client,
5699
+ auth,
5700
+ headers: requiredTeamHeaders(options),
5701
+ path: { id }
5702
+ }));
5703
+ },
5704
+ async suspend(id, options) {
5705
+ return unwrapResult(await suspendSigningCredential({
5706
+ client,
5707
+ auth,
5708
+ headers: requiredTeamHeaders(options),
5709
+ path: { id }
5710
+ }));
5711
+ },
5712
+ async revoke(id, options) {
5713
+ return unwrapResult(await revokeSigningCredential({
5714
+ client,
5715
+ auth,
5716
+ headers: requiredTeamHeaders(options),
5717
+ path: { id }
5718
+ }));
5719
+ }
5720
+ };
5721
+ }
5722
+ //#endregion
5461
5723
  //#region ../sdk/src/namespaces/signing-requests.ts
5462
5724
  function createSigningRequestsNamespace(context) {
5463
5725
  const { client, auth } = context;
@@ -5490,6 +5752,33 @@ function createSigningRequestsNamespace(context) {
5490
5752
  path: { id },
5491
5753
  body
5492
5754
  }));
5755
+ },
5756
+ async claim(id, body, options) {
5757
+ return unwrapResult(await claimSigningRequest({
5758
+ client,
5759
+ auth,
5760
+ headers: requiredTeamHeaders(options),
5761
+ path: { id },
5762
+ body
5763
+ }));
5764
+ },
5765
+ async complete(id, body, options) {
5766
+ return unwrapResult(await completeSigningRequest({
5767
+ client,
5768
+ auth,
5769
+ headers: requiredTeamHeaders(options),
5770
+ path: { id },
5771
+ body
5772
+ }));
5773
+ },
5774
+ async reject(id, body, options) {
5775
+ return unwrapResult(await rejectSigningRequest({
5776
+ client,
5777
+ auth,
5778
+ headers: requiredTeamHeaders(options),
5779
+ path: { id },
5780
+ body
5781
+ }));
5493
5782
  }
5494
5783
  };
5495
5784
  }
@@ -15751,7 +16040,7 @@ function createAgent(options) {
15751
16040
  packs: createPacksNamespace(context),
15752
16041
  entries: createEntriesNamespace(context),
15753
16042
  agents: createAgentsNamespace(context),
15754
- crypto: createCryptoNamespace(context, createSigningRequestsNamespace(context)),
16043
+ crypto: createCryptoNamespace(context, createSigningRequestsNamespace(context), createSigningCredentialsNamespace(context)),
15755
16044
  vouch: createVouchNamespace(context),
15756
16045
  auth: createAuthNamespace(context),
15757
16046
  recovery: createRecoveryNamespace(context),
@@ -15764,22 +16053,37 @@ function createAgent(options) {
15764
16053
  runtimeSlots: createRuntimeSlotsNamespace(context),
15765
16054
  runtimeSessions: createRuntimeSessionsNamespace(context),
15766
16055
  client,
15767
- getToken: () => tokenManager.getToken()
16056
+ getToken: () => {
16057
+ if (tokenManager) return tokenManager.getToken();
16058
+ if (auth) return auth();
16059
+ return Promise.reject(new MoltNetError("No token source configured", { code: "NO_TOKEN_SOURCE" }));
16060
+ }
15768
16061
  };
15769
16062
  }
15770
16063
  //#endregion
15771
16064
  //#region ../sdk/src/config.ts
15772
16065
  /**
15773
16066
  * Read MoltNet credentials from environment variables.
15774
- * Reads MOLTNET_CLIENT_ID, MOLTNET_CLIENT_SECRET, and MOLTNET_API_URL.
16067
+ * Reads MOLTNET_CLIENT_ID, MOLTNET_CLIENT_SECRET, MOLTNET_API_URL, and
16068
+ * MOLTNET_AGENT_KEY.
15775
16069
  */
15776
16070
  function readEnvCredentials() {
15777
16071
  return {
15778
16072
  clientId: process.env.MOLTNET_CLIENT_ID,
15779
16073
  clientSecret: process.env.MOLTNET_CLIENT_SECRET,
15780
- apiUrl: process.env.MOLTNET_API_URL
16074
+ apiUrl: process.env.MOLTNET_API_URL,
16075
+ agentKey: process.env.MOLTNET_AGENT_KEY
15781
16076
  };
15782
16077
  }
16078
+ /**
16079
+ * Resolve the API base URL from an ordered list of candidates, falling back to
16080
+ * the hosted default, with any trailing slash stripped. Candidates are tried in
16081
+ * order — pass them highest-precedence first (typically explicit option, then
16082
+ * env, then config file) so every caller shares one precedence rule.
16083
+ */
16084
+ function normalizeApiUrl(...candidates) {
16085
+ return (candidates.find((c) => c) ?? "https://api.themolt.net").replace(/\/$/, "");
16086
+ }
15783
16087
  //#endregion
15784
16088
  //#region ../sdk/src/credentials.ts
15785
16089
  function getConfigDir() {
@@ -15843,6 +16147,32 @@ function createRetryFetch(tokenManager, options) {
15843
16147
  return doFetch(init);
15844
16148
  };
15845
16149
  }
16150
+ /**
16151
+ * Create a fetch wrapper for agent-key (static-bearer) authentication.
16152
+ *
16153
+ * A static key cannot be refreshed, so there is no token-invalidation/replay
16154
+ * (that half of {@link createRetryFetch} is intentionally omitted). What remains
16155
+ * is orthogonal to token refresh and still matters for a long-running client:
16156
+ *
16157
+ * - **429**: delegates to `createRateLimitFetch` (Retry-After / backoff), unless
16158
+ * `retry` is `false`.
16159
+ * - **401**: the key was rejected (revoked, expired, or not authorized for the
16160
+ * requested team). Rather than silently returning a bare 401 on every call,
16161
+ * throw an actionable {@link AuthenticationError}. The key value is never
16162
+ * included in the message.
16163
+ */
16164
+ function createAgentKeyFetch(retry) {
16165
+ const rateLimitFetch = retry === false ? fetch : createRateLimitFetch({
16166
+ maxRetries: retry?.maxRateLimitRetries,
16167
+ baseDelayMs: retry?.baseDelayMs,
16168
+ maxDelayMs: retry?.maxDelayMs
16169
+ });
16170
+ return async (input, init) => {
16171
+ const response = await rateLimitFetch(input, init);
16172
+ if (response.status === 401) throw new AuthenticationError("agent key rejected (401): the key is revoked, expired, or not authorized for the requested team — re-provision the key.", { statusCode: 401 });
16173
+ return response;
16174
+ };
16175
+ }
15846
16176
  //#endregion
15847
16177
  //#region ../sdk/src/token.ts
15848
16178
  var TokenManager = class {
@@ -15902,37 +16232,76 @@ var TokenManager = class {
15902
16232
  };
15903
16233
  //#endregion
15904
16234
  //#region ../sdk/src/connect.ts
15905
- var DEFAULT_API_URL = "https://api.themolt.net";
15906
- async function resolveCredentials(options) {
16235
+ async function resolveConnection(options) {
16236
+ const env = readEnvCredentials();
16237
+ const explicitAgentKey = options.agentKey?.trim();
16238
+ if (explicitAgentKey) {
16239
+ const config = await readConfig(options.configDir);
16240
+ return {
16241
+ mode: "agentKey",
16242
+ agentKey: explicitAgentKey,
16243
+ apiUrl: normalizeApiUrl(options.apiUrl, env.apiUrl, config?.endpoints?.api)
16244
+ };
16245
+ }
15907
16246
  if (options.clientId && options.clientSecret) return {
16247
+ mode: "oauth2",
15908
16248
  clientId: options.clientId,
15909
16249
  clientSecret: options.clientSecret,
15910
- apiUrl: (options.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "")
16250
+ apiUrl: normalizeApiUrl(options.apiUrl, env.apiUrl)
15911
16251
  };
15912
- const env = readEnvCredentials();
16252
+ const envAgentKey = env.agentKey?.trim();
16253
+ if (envAgentKey) {
16254
+ const config = await readConfig(options.configDir);
16255
+ return {
16256
+ mode: "agentKey",
16257
+ agentKey: envAgentKey,
16258
+ apiUrl: normalizeApiUrl(options.apiUrl, env.apiUrl, config?.endpoints?.api)
16259
+ };
16260
+ }
15913
16261
  if (env.clientId && env.clientSecret) return {
16262
+ mode: "oauth2",
15914
16263
  clientId: env.clientId,
15915
16264
  clientSecret: env.clientSecret,
15916
- apiUrl: (env.apiUrl ?? options.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "")
16265
+ apiUrl: normalizeApiUrl(options.apiUrl, env.apiUrl)
15917
16266
  };
15918
16267
  const config = await readConfig(options.configDir);
15919
16268
  if (config?.oauth2?.client_id && config?.oauth2?.client_secret) return {
16269
+ mode: "oauth2",
15920
16270
  clientId: config.oauth2.client_id,
15921
16271
  clientSecret: config.oauth2.client_secret,
15922
- apiUrl: (options.apiUrl ?? config.endpoints?.api ?? DEFAULT_API_URL).replace(/\/$/, "")
16272
+ apiUrl: normalizeApiUrl(options.apiUrl, config.endpoints?.api)
15923
16273
  };
15924
- throw new MoltNetError("No credentials found. Provide clientId/clientSecret, set MOLTNET_CLIENT_ID/MOLTNET_CLIENT_SECRET env vars, or run `moltnet register` first.", { code: "NO_CREDENTIALS" });
16274
+ throw new MoltNetError("No credentials found. Provide an agentKey / MOLTNET_AGENT_KEY, clientId/clientSecret, set MOLTNET_CLIENT_ID/MOLTNET_CLIENT_SECRET, or run `moltnet register` first.", { code: "NO_CREDENTIALS" });
15925
16275
  }
15926
16276
  /**
15927
16277
  * Connect to MoltNet and return an authenticated Agent facade.
15928
16278
  *
15929
- * Credential resolution order:
15930
- * 1. Explicit `clientId` / `clientSecret` in options
15931
- * 2. `MOLTNET_CLIENT_ID` / `MOLTNET_CLIENT_SECRET` environment variables
15932
- * 3. Config file (`~/.config/moltnet/moltnet.json`)
16279
+ * Credential resolution, highest precedence first. Explicit in-code options —
16280
+ * of either kind always win over the environment and config file:
16281
+ * 1. Explicit `agentKey` option agent-key mode (static bearer)
16282
+ * 2. Explicit `clientId` / `clientSecret` → OAuth2 client-credentials
16283
+ * 3. `MOLTNET_AGENT_KEY` env → agent-key mode
16284
+ * 4. `MOLTNET_CLIENT_ID` / `MOLTNET_CLIENT_SECRET` env → OAuth2
16285
+ * 5. Config file (`~/.config/moltnet/moltnet.json`) → OAuth2
16286
+ *
16287
+ * In agent-key mode the key is sent directly as a bearer token — no OAuth2
16288
+ * round-trip — and 429 backoff still applies; a rejected key surfaces an
16289
+ * `AuthenticationError`.
15933
16290
  */
15934
16291
  async function connect(options = {}) {
15935
- const creds = await resolveCredentials(options);
16292
+ const resolved = await resolveConnection(options);
16293
+ if (resolved.mode === "agentKey") {
16294
+ const client = createClient({
16295
+ baseUrl: resolved.apiUrl,
16296
+ fetch: createAgentKeyFetch(options.retry)
16297
+ });
16298
+ const auth = () => Promise.resolve(resolved.agentKey);
16299
+ return createAgent({
16300
+ client,
16301
+ auth
16302
+ });
16303
+ }
16304
+ const creds = resolved;
15936
16305
  const autoToken = options.autoToken ?? true;
15937
16306
  const tokenManager = new TokenManager({
15938
16307
  clientId: creds.clientId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@themoltnet/pi-extension",
3
- "version": "0.35.2",
3
+ "version": "0.35.4",
4
4
  "type": "module",
5
5
  "description": "MoltNet pi extension — sandboxed tool execution in Gondolin VMs with MoltNet identity and persistent memory",
6
6
  "keywords": [
@@ -36,8 +36,8 @@
36
36
  "@earendil-works/gondolin": "^0.9.1",
37
37
  "@opentelemetry/api": "^1.9.0",
38
38
  "typebox": "^1.2.8",
39
- "@themoltnet/agent-runtime": "0.36.2",
40
- "@themoltnet/sdk": "0.123.0"
39
+ "@themoltnet/sdk": "0.125.0",
40
+ "@themoltnet/agent-runtime": "0.36.4"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@earendil-works/pi-coding-agent": ">=0.74.0",