@runneth/cli 0.0.0-sha.cf0e2f4e39c3.production → 0.0.0-sha.e9a1bd80922c.production

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,7 +40,7 @@ runneth send [--name default] [--timeout-ms 600000] [--stdin] -- <command...>
40
40
  runneth status [--name default]
41
41
  runneth list
42
42
  runneth close [--name default]
43
- runneth oauth login [--resource <url>] [--client-name "Runneth MCP"] [--scope <scope>] [--no-open]
43
+ runneth oauth login [--resource <url>] [--client-id|--clientid <id>] [--client-secret|--secret <value>] [--client-name "Runneth MCP"] [--scope <scope>] [--no-open]
44
44
  runneth oauth status [--resource <url>]
45
45
  runneth oauth logout [--resource <url>]
46
46
  runneth chat --workspace <workspace-id> [--api <builder-url>] [--resource <url>] [--auth mondrian|builder] [--conversation <id>]
@@ -72,12 +72,16 @@ use a different state directory.
72
72
 
73
73
  ## OAuth
74
74
 
75
- `runneth-cli oauth login` performs OAuth protected-resource discovery, dynamic
76
- client registration as a public MCP-style client, PKCE authorization, and token
77
- exchange through a local loopback callback.
75
+ `runneth-cli oauth login` performs OAuth protected-resource discovery, PKCE
76
+ authorization, and token exchange through a local loopback callback. By default
77
+ it uses dynamic client registration as a public MCP-style client. Provide
78
+ `--client-id`/`--clientid` and `--client-secret`/`--secret`, or set
79
+ `RUNNETH_OAUTH_CLIENT_ID` and `RUNNETH_OAUTH_CLIENT_SECRET`, to use a
80
+ pre-registered confidential client instead.
78
81
 
79
82
  ```bash
80
83
  runneth oauth login --resource http://localhost:4100/mcp
84
+ RUNNETH_OAUTH_CLIENT_ID=client-id RUNNETH_OAUTH_CLIENT_SECRET=client-secret runneth oauth login --resource http://localhost:4100/mcp
81
85
  runneth oauth status --resource http://localhost:4100/mcp
82
86
  ```
83
87
 
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { resolveBuildDefaultMcpResourceUrl } from "./build-defaults.js";
3
- import { B as readOAuthCredentialStatus, C as setDefaultRunnethSshTarget, D as runRunnethConversationMachineCommand, I as getOAuthAccessToken, L as loginWithOAuth, M as parseRunnethConversationArgs, N as resolveRunnethConversationOptions, P as runRunnethConversation, R as logoutOAuthCredential, S as saveRunnethSshTarget, T as runRunnethVmCopy, U as resolveSocketPath, _ as resolveRunnethSshTarget, a as normalizeSessionName, b as runOpenSsh, d as installRunnethSshAccess, f as normalizeRunnethSshTargetName, l as installRunnethSkills, m as removeRunnethSshTarget, p as readRunnethSshTargetStore, r as ensureDaemon, s as sendRunnethCliRequest, t as RunnethCliDaemon, w as assertRunnethVmCopyTargetsUseSameResource, x as runRunnethSshProxy } from "./src.js";
3
+ import { B as readOAuthCredentialStatus, C as setDefaultRunnethSshTarget, D as runRunnethConversationMachineCommand, G as resolveSocketPath, L as loginWithOAuth, M as parseRunnethConversationArgs, N as resolveRunnethConversationOptions, P as runRunnethConversation, R as logoutOAuthCredential, S as saveRunnethSshTarget, T as runRunnethVmCopy, U as resolveOAuthToken, V as resolveOAuthClientCredentialOptions, _ as resolveRunnethSshTarget, a as normalizeSessionName, b as runOpenSsh, d as installRunnethSshAccess, f as normalizeRunnethSshTargetName, l as installRunnethSkills, m as removeRunnethSshTarget, p as readRunnethSshTargetStore, r as ensureDaemon, s as sendRunnethCliRequest, t as RunnethCliDaemon, w as assertRunnethVmCopyTargetsUseSameResource, x as runRunnethSshProxy } from "./src.js";
4
4
  import { readFile, rm } from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import process$1 from "node:process";
@@ -547,8 +547,9 @@ const runRunnethSshStdio = async (options) => {
547
547
  //#region src/cli.ts
548
548
  const DEFAULT_TIMEOUT_MS = 6e5;
549
549
  const DEFAULT_OAUTH_CLIENT_NAME = "Runneth MCP";
550
- const DEFAULT_OAUTH_SCOPE = "openid profile email offline_access";
551
550
  const MAX_STDIN_BYTES = 1048576;
551
+ const RUNNETH_OAUTH_CLIENT_ID_ENV = "RUNNETH_OAUTH_CLIENT_ID";
552
+ const RUNNETH_OAUTH_CLIENT_SECRET_ENV = "RUNNETH_OAUTH_CLIENT_SECRET";
552
553
  const isRecord = (value) => {
553
554
  return typeof value === "object" && value !== null && !Array.isArray(value);
554
555
  };
@@ -620,6 +621,12 @@ const parseNumber = (rawValue, label) => {
620
621
  if (!Number.isInteger(value) || value <= 0) throw new Error(`${label} must be a positive integer`);
621
622
  return value;
622
623
  };
624
+ const resolveCliOAuthClientCredentialOptions = (parsed) => {
625
+ return resolveOAuthClientCredentialOptions({
626
+ clientId: parsed.clientId ?? process$1.env[RUNNETH_OAUTH_CLIENT_ID_ENV],
627
+ clientSecret: parsed.clientSecret ?? process$1.env[RUNNETH_OAUTH_CLIENT_SECRET_ENV]
628
+ });
629
+ };
623
630
  const parseArgs = (argv) => {
624
631
  const values = [];
625
632
  let cwd;
@@ -696,10 +703,12 @@ const parseSkillsArgs = (argv) => {
696
703
  };
697
704
  const parseOAuthArgs = (argv) => {
698
705
  const values = [];
706
+ let clientId;
699
707
  let clientName = DEFAULT_OAUTH_CLIENT_NAME;
708
+ let clientSecret;
700
709
  let openBrowser = true;
701
710
  let resourceUrl;
702
- let scope = DEFAULT_OAUTH_SCOPE;
711
+ let scope;
703
712
  let timeoutMs = DEFAULT_TIMEOUT_MS;
704
713
  let parseOptions = true;
705
714
  for (let index = 0; index < argv.length; index += 1) {
@@ -719,9 +728,17 @@ const parseOAuthArgs = (argv) => {
719
728
  return value;
720
729
  };
721
730
  switch (token) {
731
+ case "--client-id":
732
+ case "--clientid":
733
+ clientId = readValue(token);
734
+ break;
722
735
  case "--client-name":
723
736
  clientName = readValue(token);
724
737
  break;
738
+ case "--client-secret":
739
+ case "--secret":
740
+ clientSecret = readValue(token);
741
+ break;
725
742
  case "--no-open":
726
743
  openBrowser = false;
727
744
  break;
@@ -738,7 +755,9 @@ const parseOAuthArgs = (argv) => {
738
755
  }
739
756
  }
740
757
  return {
758
+ ...clientId === void 0 ? {} : { clientId },
741
759
  clientName,
760
+ ...clientSecret === void 0 ? {} : { clientSecret },
742
761
  openBrowser,
743
762
  resourceUrl,
744
763
  scope,
@@ -748,12 +767,14 @@ const parseOAuthArgs = (argv) => {
748
767
  };
749
768
  const parseSshArgs = (argv) => {
750
769
  const values = [];
770
+ let clientId;
751
771
  let clientName = DEFAULT_OAUTH_CLIENT_NAME;
772
+ let clientSecret;
752
773
  let identityFilePath;
753
774
  let makeDefault = false;
754
775
  let openBrowser = true;
755
776
  let resourceUrl;
756
- let scope = DEFAULT_OAUTH_SCOPE;
777
+ let scope;
757
778
  let sshHost;
758
779
  let sshUrl;
759
780
  let targetName;
@@ -779,9 +800,17 @@ const parseSshArgs = (argv) => {
779
800
  return value;
780
801
  };
781
802
  switch (token) {
803
+ case "--client-id":
804
+ case "--clientid":
805
+ clientId = readValue(token);
806
+ break;
782
807
  case "--client-name":
783
808
  clientName = readValue(token);
784
809
  break;
810
+ case "--client-secret":
811
+ case "--secret":
812
+ clientSecret = readValue(token);
813
+ break;
785
814
  case "--default":
786
815
  makeDefault = true;
787
816
  break;
@@ -817,7 +846,9 @@ const parseSshArgs = (argv) => {
817
846
  }
818
847
  return {
819
848
  argumentSeparatorSeen,
849
+ ...clientId === void 0 ? {} : { clientId },
820
850
  clientName,
851
+ ...clientSecret === void 0 ? {} : { clientSecret },
821
852
  ...identityFilePath === void 0 ? {} : { identityFilePath },
822
853
  makeDefault,
823
854
  openBrowser,
@@ -833,11 +864,13 @@ const parseSshArgs = (argv) => {
833
864
  };
834
865
  const parseCopyArgs = (argv) => {
835
866
  const values = [];
867
+ let clientId;
836
868
  let clientName = DEFAULT_OAUTH_CLIENT_NAME;
869
+ let clientSecret;
837
870
  let destinationTargetName;
838
871
  const ignoredPaths = [];
839
872
  let openBrowser = true;
840
- let scope = DEFAULT_OAUTH_SCOPE;
873
+ let scope;
841
874
  let sourceTargetName;
842
875
  let timeoutMs = DEFAULT_TIMEOUT_MS;
843
876
  let parseOptions = true;
@@ -858,9 +891,17 @@ const parseCopyArgs = (argv) => {
858
891
  return value;
859
892
  };
860
893
  switch (token) {
894
+ case "--client-id":
895
+ case "--clientid":
896
+ clientId = readValue(token);
897
+ break;
861
898
  case "--client-name":
862
899
  clientName = readValue(token);
863
900
  break;
901
+ case "--client-secret":
902
+ case "--secret":
903
+ clientSecret = readValue(token);
904
+ break;
864
905
  case "--from":
865
906
  sourceTargetName = normalizeRunnethSshTargetName(readValue(token));
866
907
  break;
@@ -885,7 +926,9 @@ const parseCopyArgs = (argv) => {
885
926
  if (sourceTargetName === void 0) throw new Error("runneth-cli copy requires --from <target>");
886
927
  if (destinationTargetName === void 0) throw new Error("runneth-cli copy requires --to <target>");
887
928
  return {
929
+ ...clientId === void 0 ? {} : { clientId },
888
930
  clientName,
931
+ ...clientSecret === void 0 ? {} : { clientSecret },
889
932
  destinationTargetName,
890
933
  ignoredPaths,
891
934
  openBrowser,
@@ -1001,12 +1044,12 @@ const resolveSshTargetImportEntries = (input) => {
1001
1044
  });
1002
1045
  };
1003
1046
  const resolveSshOAuthToken = async (parsed, resourceUrl) => {
1004
- if ((await readOAuthCredentialStatus({ resourceUrl })).authenticated) return await getOAuthAccessToken({ resourceUrl });
1005
- return await loginWithOAuth({
1047
+ return await resolveOAuthToken({
1006
1048
  authorizationUrlHandler: (authorizationUrl) => {
1007
1049
  process$1.stderr.write(`Authorize runneth-cli here:\n${authorizationUrl}\n`);
1008
1050
  },
1009
1051
  clientName: parsed.clientName,
1052
+ ...resolveCliOAuthClientCredentialOptions(parsed),
1010
1053
  openBrowser: parsed.openBrowser,
1011
1054
  resourceUrl,
1012
1055
  scope: parsed.scope,
@@ -1091,7 +1134,11 @@ const run = async (argv) => {
1091
1134
  " --workspace <id> Mondrian/Builder workspace id; may also use RUNNETH_WORKSPACE_ID",
1092
1135
  " --token <token> Bearer token override; omitted uses stored OAuth or starts login",
1093
1136
  " --auth <mode> mondrian or builder. Defaults to mondrian",
1137
+ " --client-id, --clientid <id>",
1138
+ " OAuth client id; may use RUNNETH_OAUTH_CLIENT_ID",
1094
1139
  " --client-name <name> OAuth dynamic client name. Defaults to Runneth MCP",
1140
+ " --client-secret, --secret <value>",
1141
+ " OAuth client secret; prefer RUNNETH_OAUTH_CLIENT_SECRET",
1095
1142
  " --conversation <id> Resume an existing conversation",
1096
1143
  " --no-open Print the OAuth URL instead of opening a browser",
1097
1144
  " --scope <scope> OAuth scope. Defaults to openid profile email offline_access",
@@ -1102,6 +1149,7 @@ const run = async (argv) => {
1102
1149
  "",
1103
1150
  "Environment:",
1104
1151
  " RUNNETH_API_URL, RUNNETH_RESOURCE_URL, RUNNETH_WORKSPACE_ID",
1152
+ " RUNNETH_OAUTH_CLIENT_ID, RUNNETH_OAUTH_CLIENT_SECRET",
1105
1153
  " RUNNETH_TOKEN, MONDRIAN_TOKEN, BUILDER_AGENT_CHAT_TOKEN",
1106
1154
  "",
1107
1155
  "Commands inside chat:",
@@ -1128,7 +1176,11 @@ const run = async (argv) => {
1128
1176
  "Usage: runneth-cli oauth <login|status|logout> [--resource <url>] [options]",
1129
1177
  "",
1130
1178
  "Options:",
1179
+ " --client-id, --clientid <id>",
1180
+ " OAuth client id; may use RUNNETH_OAUTH_CLIENT_ID",
1131
1181
  " --client-name <name> Dynamic OAuth client name",
1182
+ " --client-secret, --secret <val>",
1183
+ " OAuth client secret; prefer RUNNETH_OAUTH_CLIENT_SECRET",
1132
1184
  " --no-open Print the authorization URL without opening a browser",
1133
1185
  " --resource <url> OAuth-protected MCP resource URL, defaults to build MONDRIAN_API_URL/mcp",
1134
1186
  " --scope <scope> OAuth scopes",
@@ -1145,6 +1197,7 @@ const run = async (argv) => {
1145
1197
  process$1.stderr.write(`Authorize runneth-cli here:\n${authorizationUrl}\n`);
1146
1198
  },
1147
1199
  clientName: parsed.clientName,
1200
+ ...resolveCliOAuthClientCredentialOptions(parsed),
1148
1201
  openBrowser: parsed.openBrowser,
1149
1202
  resourceUrl,
1150
1203
  scope: parsed.scope,
@@ -1191,7 +1244,11 @@ const run = async (argv) => {
1191
1244
  " --from <target> Source SSH target name",
1192
1245
  " --to <target> Destination SSH target name",
1193
1246
  " --ignore <path> Additional relative folder/path to skip; node_modules is skipped by default",
1247
+ " --client-id, --clientid <id>",
1248
+ " OAuth client id; may use RUNNETH_OAUTH_CLIENT_ID",
1194
1249
  " --client-name <name> Dynamic OAuth client name",
1250
+ " --client-secret, --secret <val>",
1251
+ " OAuth client secret; prefer RUNNETH_OAUTH_CLIENT_SECRET",
1195
1252
  " --no-open Print the authorization URL without opening a browser",
1196
1253
  " --scope <scope> OAuth scopes",
1197
1254
  " --timeout-ms <ms> Copy command timeout",
@@ -1270,7 +1327,11 @@ const run = async (argv) => {
1270
1327
  " target Manage named Runneth SSH VM targets",
1271
1328
  "",
1272
1329
  "Options:",
1330
+ " --client-id, --clientid <id>",
1331
+ " OAuth client id; may use RUNNETH_OAUTH_CLIENT_ID",
1273
1332
  " --client-name <name> Dynamic OAuth client name",
1333
+ " --client-secret, --secret <val>",
1334
+ " OAuth client secret; prefer RUNNETH_OAUTH_CLIENT_SECRET",
1274
1335
  " --no-open Print the authorization URL without opening a browser",
1275
1336
  " --resource <url> OAuth-protected MCP resource URL, defaults to build MONDRIAN_API_URL/mcp when using --host or --ssh-url",
1276
1337
  " --scope <scope> OAuth scopes",
package/dist/index.d.ts CHANGED
@@ -7965,12 +7965,14 @@ type RunnethConversationOptions = Readonly<{
7965
7965
  type RunnethConversationParsedOptions = Readonly<{
7966
7966
  apiBaseUrl?: string;
7967
7967
  authMode: RunnethConversationAuthMode;
7968
+ clientId?: string;
7968
7969
  clientName: string;
7970
+ clientSecret?: string;
7969
7971
  conversationId?: string;
7970
7972
  openBrowser: boolean;
7971
7973
  pollIntervalMs: number;
7972
7974
  resourceUrl?: string;
7973
- scope: string;
7975
+ scope?: string;
7974
7976
  tenanthId: string;
7975
7977
  title?: string;
7976
7978
  token?: string;
@@ -8042,18 +8044,20 @@ declare const runRunnethConversationMachineCommand: ({
8042
8044
  //#endregion
8043
8045
  //#region src/oauth.d.ts
8044
8046
  type OAuthTokenEndpointAuthMethod = "client_secret_basic" | "client_secret_post" | "none";
8047
+ type OAuthGrantType = "authorization_code" | "client_credentials";
8045
8048
  type OAuthClientRegistration = Readonly<{
8046
8049
  clientId: string;
8047
8050
  clientName: string;
8048
8051
  clientSecret?: string;
8049
- redirectUri: string;
8052
+ redirectUri?: string;
8050
8053
  tokenEndpointAuthMethod: OAuthTokenEndpointAuthMethod;
8051
8054
  }>;
8052
8055
  type OAuthServerMetadata = Readonly<{
8053
8056
  authorizationEndpoint: string;
8054
8057
  issuer: string;
8055
- registrationEndpoint: string;
8058
+ registrationEndpoint?: string;
8056
8059
  tokenEndpoint: string;
8060
+ tokenEndpointAuthMethodsSupported?: readonly OAuthTokenEndpointAuthMethod[];
8057
8061
  }>;
8058
8062
  type OAuthStoredToken = Readonly<{
8059
8063
  accessToken: string;
@@ -8067,9 +8071,10 @@ type OAuthStoredCredential = Readonly<{
8067
8071
  authorizationServer: OAuthServerMetadata;
8068
8072
  client: OAuthClientRegistration;
8069
8073
  createdAt: string;
8074
+ grantType: OAuthGrantType;
8070
8075
  requestedResourceUrl: string;
8071
8076
  resource: string;
8072
- scope: string;
8077
+ scope?: string;
8073
8078
  token: OAuthStoredToken;
8074
8079
  updatedAt: string;
8075
8080
  version: 1;
@@ -8086,7 +8091,9 @@ type OAuthCredentialStatus = Readonly<{
8086
8091
  }>;
8087
8092
  type OAuthLoginOptions = Readonly<{
8088
8093
  authorizationUrlHandler?: (authorizationUrl: string) => Promise<void> | void;
8094
+ clientId?: string;
8089
8095
  clientName?: string;
8096
+ clientSecret?: string;
8090
8097
  homePath?: string;
8091
8098
  openBrowser?: boolean;
8092
8099
  resourceUrl: string;
@@ -8100,10 +8107,15 @@ type OAuthTokenResult = Readonly<{
8100
8107
  expiresAt?: string;
8101
8108
  tokenType: string;
8102
8109
  }>;
8110
+ type OAuthClientCredentialOptions = Readonly<{
8111
+ clientId?: string;
8112
+ clientSecret?: string;
8113
+ }>;
8103
8114
  declare const resolveOAuthCredentialPath: (input: {
8104
8115
  readonly homePath?: string;
8105
8116
  readonly resourceUrl: string;
8106
8117
  }) => string;
8118
+ declare const resolveOAuthClientCredentialOptions: (input: OAuthClientCredentialOptions) => OAuthClientCredentialOptions;
8107
8119
  declare const readOAuthCredential: (input: {
8108
8120
  readonly homePath?: string;
8109
8121
  readonly resourceUrl: string;
@@ -8403,4 +8415,4 @@ declare const ensureDaemon: (input: {
8403
8415
  readonly socketPath: string;
8404
8416
  }) => Promise<void>;
8405
8417
  //#endregion
8406
- export { type OAuthClientRegistration, type OAuthCredentialStatus, type OAuthLoginOptions, type OAuthServerMetadata, type OAuthStoredCredential, type OAuthStoredToken, type OAuthTokenEndpointAuthMethod, type OAuthTokenResult, type OpenSshOptions, RUNNETH_CONVERSATION_DEFAULT_POLL_INTERVAL_MS, type ResolvedRunnethSshTarget, RunnethCliDaemon, RunnethCliDaemonOptions, RunnethCliPublicSession, RunnethCliRequest, RunnethCliResponse, type RunnethConversationAuthMode, type RunnethConversationMachineCommandOptions, type RunnethConversationOptions, type RunnethConversationParsedOptions, type RunnethConversationState, type RunnethSkillAgent, type RunnethSkillInstallOptions, type RunnethSkillInstallResult, type RunnethSkillInstallTarget, type RunnethSshAppMetadata, type RunnethSshGeneratedKeyMode, type RunnethSshInstallResponse, type RunnethSshKeyMode, type RunnethSshKeyPaths, type RunnethSshProxyOptions, type RunnethSshProxyStreams, type RunnethSshSetupOptions, type RunnethSshSetupResult, type RunnethSshTarget, type RunnethSshTargetPaths, type RunnethSshTargetStore, type RunnethVmCopyOptions, type RunnethVmCopyResult, assertRunnethVmCopyTargetsUseSameResource, createCommandEnvelope, createConversation as createRunnethConversation, ensureDaemon, extractCommandResult, fetchConversationState as fetchRunnethConversationState, getOAuthAccessToken, installRunnethSkills, installRunnethSshAccess, loginWithOAuth, logoutOAuthCredential, normalizeRunnethApiBaseUrl, normalizeRunnethSshTargetName, normalizeSessionName, parseRunnethCliRequest, parseRunnethConversationArgs, parseRunnethConversationSessionRequest, readOAuthCredential, readOAuthCredentialStatus, readRunnethSshTargetStore, removeRunnethSshTarget, resolveBundledRunnethSkillPath, resolveOAuthCredentialPath, resolveRunnethCliHome, resolveRunnethConversationOptions, resolveRunnethSshAppUrl, resolveRunnethSshSharedKeyPaths, resolveRunnethSshTarget, resolveRunnethSshTargetPaths, resolveRunnethSshTargetsPath, resolveSocketPath, runOpenSsh, runRunnethConversation, runRunnethConversationMachineCommand, runRunnethSshProxy, runRunnethVmCopy, saveRunnethSshTarget, sendRunnethCliRequest, sendMessage as sendRunnethConversationMessage, setDefaultRunnethSshTarget, startDaemonProcess };
8418
+ export { type OAuthClientCredentialOptions, type OAuthClientRegistration, type OAuthCredentialStatus, type OAuthGrantType, type OAuthLoginOptions, type OAuthServerMetadata, type OAuthStoredCredential, type OAuthStoredToken, type OAuthTokenEndpointAuthMethod, type OAuthTokenResult, type OpenSshOptions, RUNNETH_CONVERSATION_DEFAULT_POLL_INTERVAL_MS, type ResolvedRunnethSshTarget, RunnethCliDaemon, RunnethCliDaemonOptions, RunnethCliPublicSession, RunnethCliRequest, RunnethCliResponse, type RunnethConversationAuthMode, type RunnethConversationMachineCommandOptions, type RunnethConversationOptions, type RunnethConversationParsedOptions, type RunnethConversationState, type RunnethSkillAgent, type RunnethSkillInstallOptions, type RunnethSkillInstallResult, type RunnethSkillInstallTarget, type RunnethSshAppMetadata, type RunnethSshGeneratedKeyMode, type RunnethSshInstallResponse, type RunnethSshKeyMode, type RunnethSshKeyPaths, type RunnethSshProxyOptions, type RunnethSshProxyStreams, type RunnethSshSetupOptions, type RunnethSshSetupResult, type RunnethSshTarget, type RunnethSshTargetPaths, type RunnethSshTargetStore, type RunnethVmCopyOptions, type RunnethVmCopyResult, assertRunnethVmCopyTargetsUseSameResource, createCommandEnvelope, createConversation as createRunnethConversation, ensureDaemon, extractCommandResult, fetchConversationState as fetchRunnethConversationState, getOAuthAccessToken, installRunnethSkills, installRunnethSshAccess, loginWithOAuth, logoutOAuthCredential, normalizeRunnethApiBaseUrl, normalizeRunnethSshTargetName, normalizeSessionName, parseRunnethCliRequest, parseRunnethConversationArgs, parseRunnethConversationSessionRequest, readOAuthCredential, readOAuthCredentialStatus, readRunnethSshTargetStore, removeRunnethSshTarget, resolveBundledRunnethSkillPath, resolveOAuthClientCredentialOptions, resolveOAuthCredentialPath, resolveRunnethCliHome, resolveRunnethConversationOptions, resolveRunnethSshAppUrl, resolveRunnethSshSharedKeyPaths, resolveRunnethSshTarget, resolveRunnethSshTargetPaths, resolveRunnethSshTargetsPath, resolveSocketPath, runOpenSsh, runRunnethConversation, runRunnethConversationMachineCommand, runRunnethSshProxy, runRunnethVmCopy, saveRunnethSshTarget, sendRunnethCliRequest, sendMessage as sendRunnethConversationMessage, setDefaultRunnethSshTarget, startDaemonProcess };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { A as fetchConversationState, B as readOAuthCredentialStatus, C as setDefaultRunnethSshTarget, D as runRunnethConversationMachineCommand, E as parseRunnethConversationSessionRequest, F as sendMessage, H as resolveRunnethCliHome, I as getOAuthAccessToken, L as loginWithOAuth, M as parseRunnethConversationArgs, N as resolveRunnethConversationOptions, O as RUNNETH_CONVERSATION_DEFAULT_POLL_INTERVAL_MS, P as runRunnethConversation, R as logoutOAuthCredential, S as saveRunnethSshTarget, T as runRunnethVmCopy, U as resolveSocketPath, V as resolveOAuthCredentialPath, _ as resolveRunnethSshTarget, a as normalizeSessionName, b as runOpenSsh, c as startDaemonProcess, d as installRunnethSshAccess, f as normalizeRunnethSshTargetName, g as resolveRunnethSshSharedKeyPaths, h as resolveRunnethSshAppUrl, i as extractCommandResult, j as normalizeRunnethApiBaseUrl, k as createConversation, l as installRunnethSkills, m as removeRunnethSshTarget, n as createCommandEnvelope, o as parseRunnethCliRequest, p as readRunnethSshTargetStore, r as ensureDaemon, s as sendRunnethCliRequest, t as RunnethCliDaemon, u as resolveBundledRunnethSkillPath, v as resolveRunnethSshTargetPaths, w as assertRunnethVmCopyTargetsUseSameResource, x as runRunnethSshProxy, y as resolveRunnethSshTargetsPath, z as readOAuthCredential } from "./src.js";
2
- export { RUNNETH_CONVERSATION_DEFAULT_POLL_INTERVAL_MS, RunnethCliDaemon, assertRunnethVmCopyTargetsUseSameResource, createCommandEnvelope, createConversation as createRunnethConversation, ensureDaemon, extractCommandResult, fetchConversationState as fetchRunnethConversationState, getOAuthAccessToken, installRunnethSkills, installRunnethSshAccess, loginWithOAuth, logoutOAuthCredential, normalizeRunnethApiBaseUrl, normalizeRunnethSshTargetName, normalizeSessionName, parseRunnethCliRequest, parseRunnethConversationArgs, parseRunnethConversationSessionRequest, readOAuthCredential, readOAuthCredentialStatus, readRunnethSshTargetStore, removeRunnethSshTarget, resolveBundledRunnethSkillPath, resolveOAuthCredentialPath, resolveRunnethCliHome, resolveRunnethConversationOptions, resolveRunnethSshAppUrl, resolveRunnethSshSharedKeyPaths, resolveRunnethSshTarget, resolveRunnethSshTargetPaths, resolveRunnethSshTargetsPath, resolveSocketPath, runOpenSsh, runRunnethConversation, runRunnethConversationMachineCommand, runRunnethSshProxy, runRunnethVmCopy, saveRunnethSshTarget, sendRunnethCliRequest, sendMessage as sendRunnethConversationMessage, setDefaultRunnethSshTarget, startDaemonProcess };
1
+ import { A as fetchConversationState, B as readOAuthCredentialStatus, C as setDefaultRunnethSshTarget, D as runRunnethConversationMachineCommand, E as parseRunnethConversationSessionRequest, F as sendMessage, G as resolveSocketPath, H as resolveOAuthCredentialPath, I as getOAuthAccessToken, L as loginWithOAuth, M as parseRunnethConversationArgs, N as resolveRunnethConversationOptions, O as RUNNETH_CONVERSATION_DEFAULT_POLL_INTERVAL_MS, P as runRunnethConversation, R as logoutOAuthCredential, S as saveRunnethSshTarget, T as runRunnethVmCopy, V as resolveOAuthClientCredentialOptions, W as resolveRunnethCliHome, _ as resolveRunnethSshTarget, a as normalizeSessionName, b as runOpenSsh, c as startDaemonProcess, d as installRunnethSshAccess, f as normalizeRunnethSshTargetName, g as resolveRunnethSshSharedKeyPaths, h as resolveRunnethSshAppUrl, i as extractCommandResult, j as normalizeRunnethApiBaseUrl, k as createConversation, l as installRunnethSkills, m as removeRunnethSshTarget, n as createCommandEnvelope, o as parseRunnethCliRequest, p as readRunnethSshTargetStore, r as ensureDaemon, s as sendRunnethCliRequest, t as RunnethCliDaemon, u as resolveBundledRunnethSkillPath, v as resolveRunnethSshTargetPaths, w as assertRunnethVmCopyTargetsUseSameResource, x as runRunnethSshProxy, y as resolveRunnethSshTargetsPath, z as readOAuthCredential } from "./src.js";
2
+ export { RUNNETH_CONVERSATION_DEFAULT_POLL_INTERVAL_MS, RunnethCliDaemon, assertRunnethVmCopyTargetsUseSameResource, createCommandEnvelope, createConversation as createRunnethConversation, ensureDaemon, extractCommandResult, fetchConversationState as fetchRunnethConversationState, getOAuthAccessToken, installRunnethSkills, installRunnethSshAccess, loginWithOAuth, logoutOAuthCredential, normalizeRunnethApiBaseUrl, normalizeRunnethSshTargetName, normalizeSessionName, parseRunnethCliRequest, parseRunnethConversationArgs, parseRunnethConversationSessionRequest, readOAuthCredential, readOAuthCredentialStatus, readRunnethSshTargetStore, removeRunnethSshTarget, resolveBundledRunnethSkillPath, resolveOAuthClientCredentialOptions, resolveOAuthCredentialPath, resolveRunnethCliHome, resolveRunnethConversationOptions, resolveRunnethSshAppUrl, resolveRunnethSshSharedKeyPaths, resolveRunnethSshTarget, resolveRunnethSshTargetPaths, resolveRunnethSshTargetsPath, resolveSocketPath, runOpenSsh, runRunnethConversation, runRunnethConversationMachineCommand, runRunnethSshProxy, runRunnethVmCopy, saveRunnethSshTarget, sendRunnethCliRequest, sendMessage as sendRunnethConversationMessage, setDefaultRunnethSshTarget, startDaemonProcess };
package/dist/src.js CHANGED
@@ -4402,6 +4402,7 @@ const routineRunFailureReasonSchema = _enum([
4402
4402
  "stopped"
4403
4403
  ]);
4404
4404
  const routineRunSkipReasonSchema = _enum(["backlog_capped", "run_in_progress"]);
4405
+ const routineModeSchema = _enum(["agent", "script"]);
4405
4406
  const isCanonicalUtcIso = (value) => {
4406
4407
  const date = new Date(value);
4407
4408
  return !Number.isNaN(date.getTime()) && date.toISOString() === value;
@@ -4472,7 +4473,9 @@ const routineBaseSchema = object({
4472
4473
  owner: object({ id: string().uuid() }).strict().nullable(),
4473
4474
  createdAt: utcDateTimeSchema,
4474
4475
  delivery: routineDeliverySchema,
4476
+ failStreak: number$1().int().min(0).nullable().default(null),
4475
4477
  lastRunAt: utcDateTimeSchema.nullable(),
4478
+ mode: routineModeSchema.default("agent"),
4476
4479
  name: routineNameSchema,
4477
4480
  nextRunAt: utcDateTimeSchema.nullable(),
4478
4481
  occurrenceCount: number$1().int().min(0),
@@ -4494,11 +4497,27 @@ const validateRoutine = (routine, ctx) => {
4494
4497
  message: "non-active routines must not have nextRunAt",
4495
4498
  path: ["nextRunAt"]
4496
4499
  });
4500
+ if (routine.mode === "script" !== (routine.failStreak !== null)) ctx.addIssue({
4501
+ code: "custom",
4502
+ message: "script mode requires a failStreak",
4503
+ path: ["failStreak"]
4504
+ });
4497
4505
  };
4498
4506
  routineBaseSchema.strict().superRefine(validateRoutine);
4499
4507
  const routineResponseSchema = routineBaseSchema.strict().superRefine(validateRoutine);
4508
+ const routineV1ResponseSchema = routineBaseSchema.omit({
4509
+ failStreak: true,
4510
+ mode: true
4511
+ }).strict().superRefine((routine, ctx) => {
4512
+ validateRoutine({
4513
+ ...routine,
4514
+ failStreak: null,
4515
+ mode: "agent"
4516
+ }, ctx);
4517
+ });
4500
4518
  const routineRunBaseSchema = object({
4501
4519
  createdAt: utcDateTimeSchema,
4520
+ executor: routineModeSchema.nullable().default(null),
4502
4521
  failureReason: routineRunFailureReasonSchema.nullable(),
4503
4522
  finishedAt: utcDateTimeSchema.nullable(),
4504
4523
  missedOccurrenceCount: number$1().int().min(0),
@@ -4506,6 +4525,7 @@ const routineRunBaseSchema = object({
4506
4525
  routineId: routineIdSchema,
4507
4526
  runId: string().uuid(),
4508
4527
  scheduledFor: utcDateTimeSchema,
4528
+ scriptError: string().trim().min(1).nullable().default(null),
4509
4529
  skipReason: routineRunSkipReasonSchema.nullable(),
4510
4530
  status: routineRunStatusSchema,
4511
4531
  submittedAt: utcDateTimeSchema.nullable(),
@@ -4520,14 +4540,14 @@ const validateRoutineRun = (run, ctx) => {
4520
4540
  message: "completed runs require submittedAt",
4521
4541
  path: ["submittedAt"]
4522
4542
  });
4523
- if (run.outcome === null) ctx.addIssue({
4543
+ if (run.executor !== "script" && run.outcome === null) ctx.addIssue({
4524
4544
  code: "custom",
4525
- message: "completed runs require an outcome",
4545
+ message: "completed agent runs require an outcome",
4526
4546
  path: ["outcome"]
4527
4547
  });
4528
- if (run.summary === null) ctx.addIssue({
4548
+ if (run.executor !== "script" && run.summary === null) ctx.addIssue({
4529
4549
  code: "custom",
4530
- message: "completed runs require a summary",
4550
+ message: "completed agent runs require a summary",
4531
4551
  path: ["summary"]
4532
4552
  });
4533
4553
  if (run.failureReason !== null) ctx.addIssue({
@@ -4634,6 +4654,40 @@ const validateRoutineRun = (run, ctx) => {
4634
4654
  path: ["skipReason"]
4635
4655
  });
4636
4656
  }
4657
+ if (run.executor === "script") {
4658
+ if (run.scriptError !== null) ctx.addIssue({
4659
+ code: "custom",
4660
+ message: "script-executed runs must not carry scriptError",
4661
+ path: ["scriptError"]
4662
+ });
4663
+ if (run.outcome !== null) ctx.addIssue({
4664
+ code: "custom",
4665
+ message: "script-executed runs must not have outcome",
4666
+ path: ["outcome"]
4667
+ });
4668
+ if (run.summary !== null) ctx.addIssue({
4669
+ code: "custom",
4670
+ message: "script-executed runs must not have summary",
4671
+ path: ["summary"]
4672
+ });
4673
+ }
4674
+ if (run.status === "scheduled" && run.executor !== null) ctx.addIssue({
4675
+ code: "custom",
4676
+ message: "scheduled runs must not have an executor",
4677
+ path: ["executor"]
4678
+ });
4679
+ if (run.status === "skipped") {
4680
+ if (run.executor !== null) ctx.addIssue({
4681
+ code: "custom",
4682
+ message: "skipped runs must not have an executor",
4683
+ path: ["executor"]
4684
+ });
4685
+ if (run.scriptError !== null) ctx.addIssue({
4686
+ code: "custom",
4687
+ message: "skipped runs must not have scriptError",
4688
+ path: ["scriptError"]
4689
+ });
4690
+ }
4637
4691
  if ((run.status === "completed" || run.status === "failed" || run.status === "skipped" || run.status === "canceled") && run.finishedAt === null) ctx.addIssue({
4638
4692
  code: "custom",
4639
4693
  message: "terminal runs require finishedAt",
@@ -4647,14 +4701,41 @@ const validateRoutineRun = (run, ctx) => {
4647
4701
  };
4648
4702
  routineRunBaseSchema.strict().superRefine(validateRoutineRun);
4649
4703
  const routineRunResponseSchema = routineRunBaseSchema.strict().superRefine(validateRoutineRun);
4704
+ const routineRunV1BaseSchema = routineRunBaseSchema.omit({
4705
+ executor: true,
4706
+ scriptError: true
4707
+ });
4708
+ const routineRunV1ResponseSchema = routineRunV1BaseSchema.strict().superRefine((run, ctx) => {
4709
+ validateRoutineRun({
4710
+ ...run,
4711
+ executor: null,
4712
+ scriptError: null
4713
+ }, ctx);
4714
+ });
4650
4715
  const routineManualRunResponseSchema = routineRunBaseSchema.extend({ trigger: literal("manual") }).strict().superRefine(validateRoutineRun);
4716
+ const routineManualRunV1ResponseSchema = routineRunV1BaseSchema.extend({ trigger: literal("manual") }).strict().superRefine((run, ctx) => {
4717
+ validateRoutineRun({
4718
+ ...run,
4719
+ executor: null,
4720
+ scriptError: null
4721
+ }, ctx);
4722
+ });
4651
4723
  object({ status: routineStatusSchema.optional() }).strict();
4652
4724
  object({
4653
4725
  cursor: string().trim().min(1).nullable().optional(),
4654
4726
  pageSize: number().int().min(1).max(100).optional()
4655
4727
  }).strict();
4656
4728
  object({ routines: array(routineResponseSchema) }).strict();
4657
- object({ routine: routineResponseSchema }).strict();
4729
+ object({
4730
+ routine: routineResponseSchema,
4731
+ script: string().nullable().default(null)
4732
+ }).strict().superRefine((response, ctx) => {
4733
+ if (response.routine.mode === "script" !== (response.script !== null)) ctx.addIssue({
4734
+ code: "custom",
4735
+ message: "script content must be attached exactly for script-mode routines",
4736
+ path: ["script"]
4737
+ });
4738
+ });
4658
4739
  object({
4659
4740
  nextCursor: string().nullable(),
4660
4741
  runs: array(routineRunResponseSchema)
@@ -4663,6 +4744,16 @@ object({
4663
4744
  routine: routineResponseSchema,
4664
4745
  run: routineManualRunResponseSchema
4665
4746
  }).strict();
4747
+ object({ routines: array(routineV1ResponseSchema) }).strict();
4748
+ object({ routine: routineV1ResponseSchema }).strict();
4749
+ object({
4750
+ nextCursor: string().nullable(),
4751
+ runs: array(routineRunV1ResponseSchema)
4752
+ }).strict();
4753
+ object({
4754
+ routine: routineV1ResponseSchema,
4755
+ run: routineManualRunV1ResponseSchema
4756
+ }).strict();
4666
4757
  //#endregion
4667
4758
  //#region ../agent-protocol/dist/agent-events.js
4668
4759
  const baseEventSchema = object({
@@ -4822,6 +4913,11 @@ const slackVisibilityEventSchema = object({
4822
4913
  status: _enum(["preparing_output", "no_response"]),
4823
4914
  toolUseId: string().min(1).optional()
4824
4915
  }).merge(baseEventSchema);
4916
+ const slackSilenceRejectedEventSchema = object({
4917
+ type: literal("slack_silence_rejected"),
4918
+ toolUseId: string().min(1),
4919
+ reason: string().min(1).optional()
4920
+ }).merge(baseEventSchema);
4825
4921
  const toolCallEventSchema = object({
4826
4922
  type: literal("tool_call"),
4827
4923
  toolUseId: string(),
@@ -4931,6 +5027,7 @@ const completeEventSchema = object({
4931
5027
  outcome: routineRunOutcomeSchema,
4932
5028
  summary: string().trim().min(1)
4933
5029
  }).strict().optional(),
5030
+ nudged: boolean().optional(),
4934
5031
  error: string().optional()
4935
5032
  }).merge(baseEventSchema);
4936
5033
  const stoppedEventSchema = object({
@@ -4963,6 +5060,7 @@ discriminatedUnion("type", [
4963
5060
  harnessTraceEventSchema,
4964
5061
  widgetEventSchema,
4965
5062
  slackVisibilityEventSchema,
5063
+ slackSilenceRejectedEventSchema,
4966
5064
  toolCallEventSchema,
4967
5065
  toolResultEventSchema,
4968
5066
  cliToolEventSchema,
@@ -4984,6 +5082,38 @@ discriminatedUnion("type", [
4984
5082
  toolName: _undefined().optional()
4985
5083
  }).strict()])
4986
5084
  ]);
5085
+ const runnethProtocolSchema = _enum([
5086
+ "chat",
5087
+ "relay",
5088
+ "events",
5089
+ "control",
5090
+ "stream"
5091
+ ]);
5092
+ const protocolVersionsSchema = array(number$1().int().positive()).min(1);
5093
+ const runnethChatVersionSchema = union([
5094
+ literal(1),
5095
+ literal(2),
5096
+ literal(3),
5097
+ literal(4),
5098
+ literal(5),
5099
+ literal(6)
5100
+ ]);
5101
+ object({
5102
+ chat: protocolVersionsSchema,
5103
+ relay: protocolVersionsSchema,
5104
+ events: protocolVersionsSchema,
5105
+ control: protocolVersionsSchema
5106
+ }).strict();
5107
+ object({
5108
+ protocol: runnethProtocolSchema,
5109
+ version: number$1().int().positive()
5110
+ }).strict();
5111
+ object({
5112
+ protocol: runnethProtocolSchema,
5113
+ version: string().trim().regex(/^[1-9]\d*$/u).transform((value) => {
5114
+ return Number.parseInt(value, 10);
5115
+ }).pipe(number$1().int().positive())
5116
+ }).strict();
4987
5117
  //#endregion
4988
5118
  //#region ../agent-protocol/dist/agent-chat-events.js
4989
5119
  const uuidSchema$1 = string().uuid();
@@ -5276,6 +5406,7 @@ object({
5276
5406
  ]),
5277
5407
  content: jsonValueSchema,
5278
5408
  sequenceNumber: number$1().int().positive(),
5409
+ runnethChatVersion: runnethChatVersionSchema.optional(),
5279
5410
  sourceSeq: number$1().int().positive().optional(),
5280
5411
  toolUseId: string().nullable(),
5281
5412
  createdDate: string(),
@@ -7514,7 +7645,7 @@ const CALLBACK_PATH = "/oauth/callback";
7514
7645
  const DEFAULT_CLIENT_NAME = "Runneth MCP";
7515
7646
  const DEFAULT_SCOPE = "openid profile email offline_access";
7516
7647
  const DEFAULT_TIMEOUT_MS = 3e5;
7517
- const LOOPBACK_HOST = "localhost";
7648
+ const LOOPBACK_HOST = "127.0.0.1";
7518
7649
  const OAUTH_CREDENTIAL_PATH_SEGMENT_LENGTH = 120;
7519
7650
  const TOKEN_REFRESH_BUFFER_MS = 6e4;
7520
7651
  const isRecord$6 = (value) => {
@@ -7546,6 +7677,13 @@ const parseStringArrayField = (record, key) => {
7546
7677
  for (const item of value) if (typeof item !== "string" || item.trim().length === 0) throw new Error(`${key} must contain non-empty strings`);
7547
7678
  return value;
7548
7679
  };
7680
+ const parseOptionalStringArrayField = (record, key) => {
7681
+ const value = record[key];
7682
+ if (value === void 0) return;
7683
+ if (!Array.isArray(value)) throw new Error(`${key} must be a string array`);
7684
+ for (const item of value) if (typeof item !== "string" || item.trim().length === 0) throw new Error(`${key} must contain non-empty strings`);
7685
+ return value;
7686
+ };
7549
7687
  const parseTokenEndpointAuthMethod = (value) => {
7550
7688
  switch (value) {
7551
7689
  case "client_secret_basic":
@@ -7554,6 +7692,39 @@ const parseTokenEndpointAuthMethod = (value) => {
7554
7692
  default: throw new Error(`Unsupported token_endpoint_auth_method: ${value}`);
7555
7693
  }
7556
7694
  };
7695
+ const parseOAuthGrantType = (value) => {
7696
+ switch (value) {
7697
+ case "authorization_code":
7698
+ case "client_credentials": return value;
7699
+ default: throw new Error(`Unsupported OAuth grant type: ${value}`);
7700
+ }
7701
+ };
7702
+ const parseOptionalOAuthGrantTypeField = (record, key) => {
7703
+ const value = parseOptionalStringField$1(record, key);
7704
+ return value === void 0 ? void 0 : parseOAuthGrantType(value);
7705
+ };
7706
+ const normalizeOptionalScope = (value) => {
7707
+ const scope = value?.trim();
7708
+ return scope === void 0 || scope.length === 0 ? void 0 : scope;
7709
+ };
7710
+ const parseKnownTokenEndpointAuthMethod = (value) => {
7711
+ switch (value) {
7712
+ case "client_secret_basic":
7713
+ case "client_secret_post":
7714
+ case "none": return value;
7715
+ default: return;
7716
+ }
7717
+ };
7718
+ const parseOptionalTokenEndpointAuthMethodsField = (record, key) => {
7719
+ const values = parseOptionalStringArrayField(record, key);
7720
+ if (values === void 0) return;
7721
+ const supportedValues = [];
7722
+ for (const value of values) {
7723
+ const supportedValue = parseKnownTokenEndpointAuthMethod(value);
7724
+ if (supportedValue !== void 0) supportedValues.push(supportedValue);
7725
+ }
7726
+ return supportedValues;
7727
+ };
7557
7728
  const toBase64Url = (buffer) => {
7558
7729
  return buffer.toString("base64url");
7559
7730
  };
@@ -7613,8 +7784,9 @@ const discoverAuthorizationServer = async (issuerUrl) => {
7613
7784
  return {
7614
7785
  authorizationEndpoint: parseStringField$1(metadata, "authorization_endpoint"),
7615
7786
  issuer: parseStringField$1(metadata, "issuer"),
7616
- registrationEndpoint: parseStringField$1(metadata, "registration_endpoint"),
7617
- tokenEndpoint: parseStringField$1(metadata, "token_endpoint")
7787
+ registrationEndpoint: parseOptionalStringField$1(metadata, "registration_endpoint"),
7788
+ tokenEndpoint: parseStringField$1(metadata, "token_endpoint"),
7789
+ tokenEndpointAuthMethodsSupported: parseOptionalTokenEndpointAuthMethodsField(metadata, "token_endpoint_auth_methods_supported")
7618
7790
  };
7619
7791
  };
7620
7792
  const resolveOAuthCredentialPath = (input) => {
@@ -7622,6 +7794,17 @@ const resolveOAuthCredentialPath = (input) => {
7622
7794
  const resourceUrl = normalizeOAuthResourceUrl$1(input.resourceUrl);
7623
7795
  return path.join(homePath, "oauth", ...encodeOAuthCredentialPathSegments(resourceUrl));
7624
7796
  };
7797
+ const resolveOAuthClientCredentialOptions = (input) => {
7798
+ const clientId = input.clientId?.trim();
7799
+ const clientSecret = input.clientSecret?.trim();
7800
+ if ((clientId === void 0 || clientId.length === 0) && (clientSecret === void 0 || clientSecret.length === 0)) return {};
7801
+ if (clientId === void 0 || clientId.length === 0) throw new Error("OAuth client secret requires a client id");
7802
+ if (clientSecret === void 0 || clientSecret.length === 0) throw new Error("OAuth client id requires a client secret");
7803
+ return {
7804
+ clientId,
7805
+ clientSecret
7806
+ };
7807
+ };
7625
7808
  const writeOAuthCredential = async (input) => {
7626
7809
  await mkdir(path.dirname(input.credentialPath), {
7627
7810
  mode: 448,
@@ -7646,20 +7829,22 @@ const parseStoredCredential = (value) => {
7646
7829
  authorizationServer: {
7647
7830
  authorizationEndpoint: parseStringField$1(authorizationServerValue, "authorizationEndpoint"),
7648
7831
  issuer: parseStringField$1(authorizationServerValue, "issuer"),
7649
- registrationEndpoint: parseStringField$1(authorizationServerValue, "registrationEndpoint"),
7650
- tokenEndpoint: parseStringField$1(authorizationServerValue, "tokenEndpoint")
7832
+ registrationEndpoint: parseOptionalStringField$1(authorizationServerValue, "registrationEndpoint"),
7833
+ tokenEndpoint: parseStringField$1(authorizationServerValue, "tokenEndpoint"),
7834
+ tokenEndpointAuthMethodsSupported: parseOptionalTokenEndpointAuthMethodsField(authorizationServerValue, "tokenEndpointAuthMethodsSupported")
7651
7835
  },
7652
7836
  client: {
7653
7837
  clientId: parseStringField$1(clientValue, "clientId"),
7654
7838
  clientName: parseStringField$1(clientValue, "clientName"),
7655
7839
  clientSecret: parseOptionalStringField$1(clientValue, "clientSecret"),
7656
- redirectUri: parseStringField$1(clientValue, "redirectUri"),
7840
+ redirectUri: parseOptionalStringField$1(clientValue, "redirectUri"),
7657
7841
  tokenEndpointAuthMethod: parseTokenEndpointAuthMethod(parseStringField$1(clientValue, "tokenEndpointAuthMethod"))
7658
7842
  },
7659
7843
  createdAt: parseStringField$1(value, "createdAt"),
7844
+ grantType: parseOptionalOAuthGrantTypeField(value, "grantType") ?? "authorization_code",
7660
7845
  requestedResourceUrl: parseStringField$1(value, "requestedResourceUrl"),
7661
7846
  resource: parseStringField$1(value, "resource"),
7662
- scope: parseStringField$1(value, "scope"),
7847
+ scope: parseOptionalStringField$1(value, "scope"),
7663
7848
  token: {
7664
7849
  accessToken: parseStringField$1(tokenValue, "accessToken"),
7665
7850
  expiresAt: parseOptionalStringField$1(tokenValue, "expiresAt"),
@@ -7672,6 +7857,25 @@ const parseStoredCredential = (value) => {
7672
7857
  version: 1
7673
7858
  };
7674
7859
  };
7860
+ const resolveOAuthToken = async (options) => {
7861
+ const clientCredentials = resolveOAuthClientCredentialOptions({
7862
+ clientId: options.clientId,
7863
+ clientSecret: options.clientSecret
7864
+ });
7865
+ if (clientCredentials.clientId !== void 0 && clientCredentials.clientSecret !== void 0) return await loginWithOAuth({
7866
+ ...options,
7867
+ clientId: clientCredentials.clientId,
7868
+ clientSecret: clientCredentials.clientSecret
7869
+ });
7870
+ if ((await readOAuthCredentialStatus({
7871
+ homePath: options.homePath,
7872
+ resourceUrl: options.resourceUrl
7873
+ })).authenticated) return await getOAuthAccessToken({
7874
+ homePath: options.homePath,
7875
+ resourceUrl: options.resourceUrl
7876
+ });
7877
+ return await loginWithOAuth(options);
7878
+ };
7675
7879
  const readOAuthCredential = async (input) => {
7676
7880
  const credentialPath = resolveOAuthCredentialPath(input);
7677
7881
  try {
@@ -7785,7 +7989,9 @@ const closeServer = async (server) => {
7785
7989
  });
7786
7990
  };
7787
7991
  const registerOAuthClient = async (input) => {
7788
- const response = await fetchJsonObject(input.metadata.registrationEndpoint, {
7992
+ const registrationEndpoint = input.metadata.registrationEndpoint;
7993
+ if (registrationEndpoint === void 0) throw new Error("OAuth authorization server does not support dynamic client registration; provide --client-id and --client-secret");
7994
+ const response = await fetchJsonObject(registrationEndpoint, {
7789
7995
  body: JSON.stringify({
7790
7996
  client_name: input.clientName,
7791
7997
  grant_types: ["authorization_code", "refresh_token"],
@@ -7809,6 +8015,56 @@ const registerOAuthClient = async (input) => {
7809
8015
  tokenEndpointAuthMethod: parseTokenEndpointAuthMethod(parseStringField$1(response, "token_endpoint_auth_method"))
7810
8016
  };
7811
8017
  };
8018
+ const requireOAuthClientSecret = (client) => {
8019
+ if (client.clientSecret === void 0) throw new Error(`OAuth client ${client.clientId} requires ${client.tokenEndpointAuthMethod} but has no client secret`);
8020
+ return client.clientSecret;
8021
+ };
8022
+ const requireOAuthClientRedirectUri = (client) => {
8023
+ if (client.redirectUri === void 0) throw new Error(`OAuth client ${client.clientId} requires authorization_code but has no redirect URI`);
8024
+ return client.redirectUri;
8025
+ };
8026
+ const buildOAuthClientAuthenticationHeaders = (input) => {
8027
+ switch (input.client.tokenEndpointAuthMethod) {
8028
+ case "none": return {};
8029
+ case "client_secret_post":
8030
+ input.body.set("client_secret", requireOAuthClientSecret(input.client));
8031
+ return {};
8032
+ case "client_secret_basic": {
8033
+ const encodedClientId = formUrlEncode(input.client.clientId);
8034
+ const encodedClientSecret = formUrlEncode(requireOAuthClientSecret(input.client));
8035
+ return { Authorization: `Basic ${Buffer.from(`${encodedClientId}:${encodedClientSecret}`, "utf8").toString("base64")}` };
8036
+ }
8037
+ default: {
8038
+ const exhaustive = input.client.tokenEndpointAuthMethod;
8039
+ throw new Error(`Unsupported OAuth client auth method: ${exhaustive}`);
8040
+ }
8041
+ }
8042
+ };
8043
+ const formUrlEncode = (value) => {
8044
+ const body = new URLSearchParams();
8045
+ body.set("value", value);
8046
+ return body.toString().slice(6);
8047
+ };
8048
+ const resolveClientSecretAuthMethod = (metadata) => {
8049
+ const supportedMethods = metadata.tokenEndpointAuthMethodsSupported;
8050
+ if (supportedMethods === void 0 || supportedMethods.includes("client_secret_basic")) return "client_secret_basic";
8051
+ if (supportedMethods.includes("client_secret_post")) return "client_secret_post";
8052
+ throw new Error("OAuth authorization server does not support client secret authentication");
8053
+ };
8054
+ const resolveProvidedOAuthClient = (input) => {
8055
+ const clientId = input.clientId?.trim();
8056
+ const clientSecret = input.clientSecret?.trim();
8057
+ if ((clientId === void 0 || clientId.length === 0) && (clientSecret === void 0 || clientSecret.length === 0)) return null;
8058
+ if (clientId === void 0 || clientId.length === 0) throw new Error("OAuth client secret requires a client id");
8059
+ if (clientSecret === void 0 || clientSecret.length === 0) throw new Error("OAuth client id requires a client secret");
8060
+ return {
8061
+ clientId,
8062
+ clientName: input.clientName,
8063
+ clientSecret,
8064
+ redirectUri: input.redirectUri,
8065
+ tokenEndpointAuthMethod: resolveClientSecretAuthMethod(input.metadata)
8066
+ };
8067
+ };
7812
8068
  const openSystemBrowser = async (url) => {
7813
8069
  const command = process$1.platform === "darwin" ? "open" : process$1.platform === "win32" ? "cmd" : "xdg-open";
7814
8070
  const args = process$1.platform === "win32" ? [
@@ -7834,7 +8090,7 @@ const buildAuthorizationUrl = (input) => {
7834
8090
  authorizationUrl.searchParams.set("client_id", input.client.clientId);
7835
8091
  authorizationUrl.searchParams.set("code_challenge", input.pkceChallenge);
7836
8092
  authorizationUrl.searchParams.set("code_challenge_method", "S256");
7837
- authorizationUrl.searchParams.set("redirect_uri", input.client.redirectUri);
8093
+ authorizationUrl.searchParams.set("redirect_uri", requireOAuthClientRedirectUri(input.client));
7838
8094
  authorizationUrl.searchParams.set("response_type", "code");
7839
8095
  authorizationUrl.searchParams.set("scope", input.scope);
7840
8096
  authorizationUrl.searchParams.set("prompt", "consent");
@@ -7883,30 +8139,65 @@ const requestOAuthToken = async (input) => {
7883
8139
  redirect_uri: input.redirectUri,
7884
8140
  resource: input.resource
7885
8141
  });
7886
- if (input.client.clientSecret !== void 0) body.set("client_secret", input.client.clientSecret);
8142
+ const clientAuthHeaders = buildOAuthClientAuthenticationHeaders({
8143
+ body,
8144
+ client: input.client
8145
+ });
7887
8146
  return parseTokenResponse(await fetchJsonObject(input.metadata.tokenEndpoint, {
7888
8147
  body,
7889
8148
  headers: {
7890
8149
  Accept: "application/json",
8150
+ ...clientAuthHeaders,
7891
8151
  "Content-Type": "application/x-www-form-urlencoded"
7892
8152
  },
7893
8153
  method: "POST"
7894
8154
  }, "OAuth token request"), Date.now());
7895
8155
  };
8156
+ const requestOAuthClientCredentialsToken = async (input) => {
8157
+ const body = new URLSearchParams({
8158
+ client_id: input.client.clientId,
8159
+ grant_type: "client_credentials",
8160
+ resource: input.resource
8161
+ });
8162
+ if (input.scope !== void 0) body.set("scope", input.scope);
8163
+ const clientAuthHeaders = buildOAuthClientAuthenticationHeaders({
8164
+ body,
8165
+ client: input.client
8166
+ });
8167
+ return parseTokenResponse(await fetchJsonObject(input.metadata.tokenEndpoint, {
8168
+ body,
8169
+ headers: {
8170
+ Accept: "application/json",
8171
+ ...clientAuthHeaders,
8172
+ "Content-Type": "application/x-www-form-urlencoded"
8173
+ },
8174
+ method: "POST"
8175
+ }, "OAuth client credentials token request"), Date.now());
8176
+ };
7896
8177
  const refreshOAuthToken = async (input) => {
8178
+ if (input.credential.grantType === "client_credentials") return await requestOAuthClientCredentialsToken({
8179
+ client: input.credential.client,
8180
+ metadata: input.credential.authorizationServer,
8181
+ resource: input.credential.resource,
8182
+ scope: input.credential.scope
8183
+ });
7897
8184
  if (input.credential.token.refreshToken === void 0) throw new Error("Stored OAuth credential is expired and has no refresh token");
7898
8185
  const body = new URLSearchParams({
7899
8186
  client_id: input.credential.client.clientId,
7900
8187
  grant_type: "refresh_token",
7901
8188
  refresh_token: input.credential.token.refreshToken,
7902
- resource: input.credential.resource,
7903
- scope: input.credential.scope
8189
+ resource: input.credential.resource
8190
+ });
8191
+ if (input.credential.scope !== void 0) body.set("scope", input.credential.scope);
8192
+ const clientAuthHeaders = buildOAuthClientAuthenticationHeaders({
8193
+ body,
8194
+ client: input.credential.client
7904
8195
  });
7905
- if (input.credential.client.clientSecret !== void 0) body.set("client_secret", input.credential.client.clientSecret);
7906
8196
  const refreshed = parseTokenResponse(await fetchJsonObject(input.credential.authorizationServer.tokenEndpoint, {
7907
8197
  body,
7908
8198
  headers: {
7909
8199
  Accept: "application/json",
8200
+ ...clientAuthHeaders,
7910
8201
  "Content-Type": "application/x-www-form-urlencoded"
7911
8202
  },
7912
8203
  method: "POST"
@@ -7922,22 +8213,62 @@ const tokenIsFresh = (token) => {
7922
8213
  };
7923
8214
  const loginWithOAuth = async (options) => {
7924
8215
  const requestedResourceUrl = normalizeOAuthResourceUrl$1(options.resourceUrl);
7925
- const scope = options.scope?.trim() || DEFAULT_SCOPE;
8216
+ const authorizationCodeScope = normalizeOptionalScope(options.scope) ?? DEFAULT_SCOPE;
8217
+ const clientCredentialsScope = normalizeOptionalScope(options.scope);
7926
8218
  const clientName = options.clientName?.trim() || DEFAULT_CLIENT_NAME;
7927
8219
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
7928
- const callbackServer = await startLoopbackCallbackServer();
7929
8220
  const credentialPath = resolveOAuthCredentialPath({
7930
8221
  homePath: options.homePath,
7931
8222
  resourceUrl: requestedResourceUrl
7932
8223
  });
8224
+ const protectedResource = await discoverProtectedResource(requestedResourceUrl);
8225
+ const authorizationServer = await discoverAuthorizationServer(protectedResource.authorizationServers[0]);
8226
+ const providedClient = resolveProvidedOAuthClient({
8227
+ clientId: options.clientId,
8228
+ clientName,
8229
+ clientSecret: options.clientSecret,
8230
+ metadata: authorizationServer,
8231
+ redirectUri: void 0
8232
+ });
8233
+ if (providedClient !== null) {
8234
+ const token = await requestOAuthClientCredentialsToken({
8235
+ client: providedClient,
8236
+ metadata: authorizationServer,
8237
+ resource: protectedResource.resource,
8238
+ scope: clientCredentialsScope
8239
+ });
8240
+ const now = (/* @__PURE__ */ new Date()).toISOString();
8241
+ const credential = {
8242
+ authorizationServer,
8243
+ client: providedClient,
8244
+ createdAt: now,
8245
+ grantType: "client_credentials",
8246
+ requestedResourceUrl,
8247
+ resource: protectedResource.resource,
8248
+ scope: clientCredentialsScope,
8249
+ token,
8250
+ updatedAt: now,
8251
+ version: 1
8252
+ };
8253
+ await writeOAuthCredential({
8254
+ credential,
8255
+ credentialPath
8256
+ });
8257
+ return {
8258
+ accessToken: token.accessToken,
8259
+ credential,
8260
+ credentialPath,
8261
+ expiresAt: token.expiresAt,
8262
+ tokenType: token.tokenType
8263
+ };
8264
+ }
8265
+ const callbackServer = await startLoopbackCallbackServer();
7933
8266
  try {
7934
- const protectedResource = await discoverProtectedResource(requestedResourceUrl);
7935
- const authorizationServer = await discoverAuthorizationServer(protectedResource.authorizationServers[0]);
7936
8267
  const client = await registerOAuthClient({
7937
8268
  clientName,
7938
8269
  metadata: authorizationServer,
7939
8270
  redirectUri: callbackServer.redirectUri,
7940
- scope
8271
+ scope: authorizationCodeScope
7941
8272
  });
7942
8273
  const state = toBase64Url(randomBytes(32));
7943
8274
  const pkce = createPkcePair();
@@ -7945,7 +8276,7 @@ const loginWithOAuth = async (options) => {
7945
8276
  client,
7946
8277
  metadata: authorizationServer,
7947
8278
  pkceChallenge: pkce.challenge,
7948
- scope,
8279
+ scope: authorizationCodeScope,
7949
8280
  state
7950
8281
  });
7951
8282
  await options.authorizationUrlHandler?.(authorizationUrl);
@@ -7966,9 +8297,10 @@ const loginWithOAuth = async (options) => {
7966
8297
  authorizationServer,
7967
8298
  client,
7968
8299
  createdAt: now,
8300
+ grantType: "authorization_code",
7969
8301
  requestedResourceUrl,
7970
8302
  resource: protectedResource.resource,
7971
- scope,
8303
+ scope: authorizationCodeScope,
7972
8304
  token,
7973
8305
  updatedAt: now,
7974
8306
  version: 1
@@ -8021,9 +8353,10 @@ const getOAuthAccessToken = async (input) => {
8021
8353
  //#region src/conversation.ts
8022
8354
  const DEFAULT_POLL_INTERVAL_MS = 1e3;
8023
8355
  const DEFAULT_OAUTH_CLIENT_NAME = "Runneth MCP";
8024
- const DEFAULT_OAUTH_SCOPE = "openid profile email offline_access";
8025
8356
  const DEFAULT_OAUTH_TIMEOUT_MS = 6e5;
8026
8357
  const MIN_POLL_INTERVAL_MS = 250;
8358
+ const RUNNETH_OAUTH_CLIENT_ID_ENV = "RUNNETH_OAUTH_CLIENT_ID";
8359
+ const RUNNETH_OAUTH_CLIENT_SECRET_ENV = "RUNNETH_OAUTH_CLIENT_SECRET";
8027
8360
  const SANDBOX_PREPARING_RETRY_TIMEOUT_MS = 18e4;
8028
8361
  const TERMINAL_MESSAGE_STATUSES$1 = new Set([
8029
8362
  "completed",
@@ -8138,16 +8471,24 @@ const apiFetch = async (options, input) => {
8138
8471
  return parseApiDataEnvelope(body, input.schema).data;
8139
8472
  }
8140
8473
  };
8474
+ const resolveCliOAuthClientCredentialOptions = (parsed) => {
8475
+ return resolveOAuthClientCredentialOptions({
8476
+ clientId: parsed.clientId ?? process.env[RUNNETH_OAUTH_CLIENT_ID_ENV],
8477
+ clientSecret: parsed.clientSecret ?? process.env[RUNNETH_OAUTH_CLIENT_SECRET_ENV]
8478
+ });
8479
+ };
8141
8480
  const parseRunnethConversationArgs = (argv, parseNumber) => {
8142
8481
  const values = [];
8143
8482
  let apiBaseUrl;
8144
8483
  let authMode = "mondrian";
8484
+ let clientId;
8145
8485
  let clientName = DEFAULT_OAUTH_CLIENT_NAME;
8486
+ let clientSecret;
8146
8487
  let conversationId;
8147
8488
  let openBrowser = true;
8148
8489
  let pollIntervalMs = DEFAULT_POLL_INTERVAL_MS;
8149
8490
  let resourceUrl;
8150
- let scope = DEFAULT_OAUTH_SCOPE;
8491
+ let scope;
8151
8492
  let tenanthId = "motion";
8152
8493
  let title;
8153
8494
  let token;
@@ -8180,9 +8521,17 @@ const parseRunnethConversationArgs = (argv, parseNumber) => {
8180
8521
  authMode = value;
8181
8522
  break;
8182
8523
  }
8524
+ case "--client-id":
8525
+ case "--clientid":
8526
+ clientId = readValue(tokenValue);
8527
+ break;
8183
8528
  case "--client-name":
8184
8529
  clientName = readValue(tokenValue);
8185
8530
  break;
8531
+ case "--client-secret":
8532
+ case "--secret":
8533
+ clientSecret = readValue(tokenValue);
8534
+ break;
8186
8535
  case "--conversation":
8187
8536
  conversationId = readValue(tokenValue);
8188
8537
  break;
@@ -8220,7 +8569,9 @@ const parseRunnethConversationArgs = (argv, parseNumber) => {
8220
8569
  return {
8221
8570
  apiBaseUrl,
8222
8571
  authMode,
8572
+ ...clientId === void 0 ? {} : { clientId },
8223
8573
  clientName,
8574
+ ...clientSecret === void 0 ? {} : { clientSecret },
8224
8575
  conversationId,
8225
8576
  openBrowser,
8226
8577
  pollIntervalMs,
@@ -8246,11 +8597,12 @@ const resolveRunnethConversationResourceUrl = (parsed) => {
8246
8597
  return normalizeOAuthResourceUrl(resourceUrl);
8247
8598
  };
8248
8599
  const resolveOAuthAccessToken = async (parsed, resourceUrl) => {
8249
- const token = (await readOAuthCredentialStatus({ resourceUrl })).authenticated ? await getOAuthAccessToken({ resourceUrl }) : await loginWithOAuth({
8600
+ const token = await resolveOAuthToken({
8250
8601
  authorizationUrlHandler: (authorizationUrl) => {
8251
8602
  process.stderr.write(`Authorize runneth-cli chat here:\n${authorizationUrl}\n`);
8252
8603
  },
8253
8604
  clientName: parsed.clientName,
8605
+ ...resolveCliOAuthClientCredentialOptions(parsed),
8254
8606
  openBrowser: parsed.openBrowser,
8255
8607
  resourceUrl,
8256
8608
  scope: parsed.scope,
@@ -9695,8 +10047,14 @@ const runRunnethConversationMachineCommand = async ({ argv, parseNumber, streams
9695
10047
  " --workspace <id> Mondrian/Builder workspace id",
9696
10048
  " --token <token> Bearer token override",
9697
10049
  " --auth <mode> mondrian or builder. Defaults to mondrian",
10050
+ " --client-id, --clientid <id>",
10051
+ " OAuth client id; may use RUNNETH_OAUTH_CLIENT_ID",
10052
+ " --client-secret, --secret <value>",
10053
+ " OAuth client secret; prefer RUNNETH_OAUTH_CLIENT_SECRET",
9698
10054
  " --conversation <id> Required for send and state",
10055
+ " --no-open Print the OAuth URL instead of opening a browser",
9699
10056
  " --poll-interval-ms <ms> State refresh interval. Defaults to 1000",
10057
+ " --scope <scope> OAuth scope. Defaults to openid profile email offline_access",
9700
10058
  " --tenanth <id> Tenant route id. Defaults to motion",
9701
10059
  "",
9702
10060
  "Machine options:",
@@ -11287,4 +11645,4 @@ const ensureDaemon = async (input) => {
11287
11645
  throw new Error("Timed out waiting for runneth-cli daemon to start");
11288
11646
  };
11289
11647
  //#endregion
11290
- export { fetchConversationState as A, readOAuthCredentialStatus as B, setDefaultRunnethSshTarget as C, runRunnethConversationMachineCommand as D, parseRunnethConversationSessionRequest as E, sendMessage as F, resolveRunnethCliHome as H, getOAuthAccessToken as I, loginWithOAuth as L, parseRunnethConversationArgs as M, resolveRunnethConversationOptions as N, RUNNETH_CONVERSATION_DEFAULT_POLL_INTERVAL_MS as O, runRunnethConversation as P, logoutOAuthCredential as R, saveRunnethSshTarget as S, runRunnethVmCopy as T, resolveSocketPath as U, resolveOAuthCredentialPath as V, resolveRunnethSshTarget as _, normalizeSessionName as a, runOpenSsh as b, startDaemonProcess as c, installRunnethSshAccess as d, normalizeRunnethSshTargetName as f, resolveRunnethSshSharedKeyPaths as g, resolveRunnethSshAppUrl as h, extractCommandResult as i, normalizeRunnethApiBaseUrl as j, createConversation as k, installRunnethSkills as l, removeRunnethSshTarget as m, createCommandEnvelope as n, parseRunnethCliRequest as o, readRunnethSshTargetStore as p, ensureDaemon as r, sendRunnethCliRequest as s, RunnethCliDaemon as t, resolveBundledRunnethSkillPath as u, resolveRunnethSshTargetPaths as v, assertRunnethVmCopyTargetsUseSameResource as w, runRunnethSshProxy as x, resolveRunnethSshTargetsPath as y, readOAuthCredential as z };
11648
+ export { fetchConversationState as A, readOAuthCredentialStatus as B, setDefaultRunnethSshTarget as C, runRunnethConversationMachineCommand as D, parseRunnethConversationSessionRequest as E, sendMessage as F, resolveSocketPath as G, resolveOAuthCredentialPath as H, getOAuthAccessToken as I, loginWithOAuth as L, parseRunnethConversationArgs as M, resolveRunnethConversationOptions as N, RUNNETH_CONVERSATION_DEFAULT_POLL_INTERVAL_MS as O, runRunnethConversation as P, logoutOAuthCredential as R, saveRunnethSshTarget as S, runRunnethVmCopy as T, resolveOAuthToken as U, resolveOAuthClientCredentialOptions as V, resolveRunnethCliHome as W, resolveRunnethSshTarget as _, normalizeSessionName as a, runOpenSsh as b, startDaemonProcess as c, installRunnethSshAccess as d, normalizeRunnethSshTargetName as f, resolveRunnethSshSharedKeyPaths as g, resolveRunnethSshAppUrl as h, extractCommandResult as i, normalizeRunnethApiBaseUrl as j, createConversation as k, installRunnethSkills as l, removeRunnethSshTarget as m, createCommandEnvelope as n, parseRunnethCliRequest as o, readRunnethSshTargetStore as p, ensureDaemon as r, sendRunnethCliRequest as s, RunnethCliDaemon as t, resolveBundledRunnethSkillPath as u, resolveRunnethSshTargetPaths as v, assertRunnethVmCopyTargetsUseSameResource as w, runRunnethSshProxy as x, resolveRunnethSshTargetsPath as y, readOAuthCredential as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runneth/cli",
3
- "version": "0.0.0-sha.cf0e2f4e39c3.production",
3
+ "version": "0.0.0-sha.e9a1bd80922c.production",
4
4
  "type": "module",
5
5
  "description": "Fast persistent local shell sessions for coding agents",
6
6
  "license": "UNLICENSED",