@gopherhole/cli 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.js +65 -14
  2. package/package.json +1 -1
  3. package/src/index.ts +68 -14
package/dist/index.js CHANGED
@@ -871,6 +871,9 @@ ${chalk_1.default.bold('Examples:')}
871
871
  $ gopherhole agents config agent-abc123 --no-auto-approve
872
872
  $ gopherhole agents config agent-abc123 --price 0.01 --price-unit request
873
873
  $ gopherhole agents config agent-abc123 --visibility public
874
+ $ gopherhole agents config agent-abc123 --alias support
875
+ $ gopherhole agents config agent-abc123 --email-enabled
876
+ $ gopherhole agents config agent-abc123 --no-email-enabled
874
877
  `)
875
878
  .option('--auto-approve', 'Enable auto-approve (instant access for marketplace)')
876
879
  .option('--no-auto-approve', 'Disable auto-approve (require manual approval)')
@@ -881,6 +884,9 @@ ${chalk_1.default.bold('Examples:')}
881
884
  .option('--category <category>', 'Set category')
882
885
  .option('--tags <tags>', 'Set tags (comma-separated)')
883
886
  .option('--description <text>', 'Update description')
887
+ .option('--alias <alias>', 'Set email alias (<alias>[.<tenant-slug>]@gopherhole.io). Triggers 30-day grace redirect from the previous alias if email is enabled')
888
+ .option('--email-enabled', 'Enable inbound + outbound email for this agent (requires an alias)')
889
+ .option('--no-email-enabled', 'Disable email for this agent (inbound rejects with 550, Postie refuses to send)')
884
890
  .action(async (agentId, options) => {
885
891
  const sessionId = config.get('sessionId');
886
892
  if (!sessionId) {
@@ -921,26 +927,65 @@ ${chalk_1.default.bold('Examples:')}
921
927
  if (options.description) {
922
928
  body.description = options.description;
923
929
  }
924
- if (Object.keys(body).length === 0) {
930
+ const aliasChange = options.alias;
931
+ const emailEnabledChange = options.emailEnabled;
932
+ if (Object.keys(body).length === 0 && aliasChange === undefined && emailEnabledChange === undefined) {
925
933
  console.log(chalk_1.default.yellow('No changes specified.'));
926
934
  console.log(chalk_1.default.gray('Use --help to see available options.'));
927
935
  return;
928
936
  }
929
937
  const spinner = (0, ora_1.default)('Updating agent config...').start();
930
- log('PATCH /agents/' + agentId, body);
931
938
  try {
932
- const res = await fetch(`${API_URL}/agents/${agentId}`, {
933
- method: 'PATCH',
934
- headers: {
935
- 'Content-Type': 'application/json',
936
- 'X-Session-ID': sessionId,
937
- },
938
- body: JSON.stringify(body),
939
- });
940
- if (!res.ok) {
941
- const err = await res.json();
942
- logError('config', err);
943
- throw new Error(err.error || 'Failed to update agent');
939
+ if (Object.keys(body).length > 0) {
940
+ log('PATCH /agents/' + agentId, body);
941
+ const res = await fetch(`${API_URL}/agents/${agentId}`, {
942
+ method: 'PATCH',
943
+ headers: {
944
+ 'Content-Type': 'application/json',
945
+ 'X-Session-ID': sessionId,
946
+ },
947
+ body: JSON.stringify(body),
948
+ });
949
+ if (!res.ok) {
950
+ const err = await res.json();
951
+ logError('config', err);
952
+ throw new Error(err.error || 'Failed to update agent');
953
+ }
954
+ }
955
+ // Alias rename has its own endpoint because it also writes the
956
+ // 30-day grace redirect into agent_alias_history.
957
+ if (aliasChange !== undefined) {
958
+ log('PATCH /agents/' + agentId + '/alias', { alias: aliasChange });
959
+ const res = await fetch(`${API_URL}/agents/${agentId}/alias`, {
960
+ method: 'PATCH',
961
+ headers: {
962
+ 'Content-Type': 'application/json',
963
+ 'X-Session-ID': sessionId,
964
+ },
965
+ body: JSON.stringify({ alias: aliasChange }),
966
+ });
967
+ if (!res.ok) {
968
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
969
+ logError('alias', err);
970
+ throw new Error(err.error || 'Failed to set alias');
971
+ }
972
+ }
973
+ // Email toggle is a dedicated endpoint that enforces alias-first.
974
+ if (emailEnabledChange !== undefined) {
975
+ log('PATCH /agents/' + agentId + '/email-enabled', { enabled: emailEnabledChange });
976
+ const res = await fetch(`${API_URL}/agents/${agentId}/email-enabled`, {
977
+ method: 'PATCH',
978
+ headers: {
979
+ 'Content-Type': 'application/json',
980
+ 'X-Session-ID': sessionId,
981
+ },
982
+ body: JSON.stringify({ enabled: emailEnabledChange }),
983
+ });
984
+ if (!res.ok) {
985
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
986
+ logError('email-enabled', err);
987
+ throw new Error(err.error || 'Failed to toggle email');
988
+ }
944
989
  }
945
990
  spinner.succeed('Agent config updated');
946
991
  // Show what was changed
@@ -969,6 +1014,12 @@ ${chalk_1.default.bold('Examples:')}
969
1014
  const desc = body.description;
970
1015
  changes.push(` Description: ${chalk_1.default.gray(desc.slice(0, 50))}${desc.length > 50 ? '...' : ''}`);
971
1016
  }
1017
+ if (aliasChange !== undefined) {
1018
+ changes.push(` Alias: ${brand.green(aliasChange)}`);
1019
+ }
1020
+ if (emailEnabledChange !== undefined) {
1021
+ changes.push(` Email: ${emailEnabledChange ? brand.green('enabled 📬') : chalk_1.default.gray('disabled')}`);
1022
+ }
972
1023
  if (changes.length > 0) {
973
1024
  console.log('');
974
1025
  console.log(chalk_1.default.bold('Changes:'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gopherhole/cli",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "GopherHole CLI - Connect AI agents to the world",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -968,6 +968,9 @@ ${chalk.bold('Examples:')}
968
968
  $ gopherhole agents config agent-abc123 --no-auto-approve
969
969
  $ gopherhole agents config agent-abc123 --price 0.01 --price-unit request
970
970
  $ gopherhole agents config agent-abc123 --visibility public
971
+ $ gopherhole agents config agent-abc123 --alias support
972
+ $ gopherhole agents config agent-abc123 --email-enabled
973
+ $ gopherhole agents config agent-abc123 --no-email-enabled
971
974
  `)
972
975
  .option('--auto-approve', 'Enable auto-approve (instant access for marketplace)')
973
976
  .option('--no-auto-approve', 'Disable auto-approve (require manual approval)')
@@ -978,6 +981,9 @@ ${chalk.bold('Examples:')}
978
981
  .option('--category <category>', 'Set category')
979
982
  .option('--tags <tags>', 'Set tags (comma-separated)')
980
983
  .option('--description <text>', 'Update description')
984
+ .option('--alias <alias>', 'Set email alias (<alias>[.<tenant-slug>]@gopherhole.io). Triggers 30-day grace redirect from the previous alias if email is enabled')
985
+ .option('--email-enabled', 'Enable inbound + outbound email for this agent (requires an alias)')
986
+ .option('--no-email-enabled', 'Disable email for this agent (inbound rejects with 550, Postie refuses to send)')
981
987
  .action(async (agentId, options) => {
982
988
  const sessionId = config.get('sessionId') as string;
983
989
  if (!sessionId) {
@@ -1021,29 +1027,71 @@ ${chalk.bold('Examples:')}
1021
1027
  body.description = options.description;
1022
1028
  }
1023
1029
 
1024
- if (Object.keys(body).length === 0) {
1030
+ const aliasChange: string | undefined = options.alias;
1031
+ const emailEnabledChange: boolean | undefined = options.emailEnabled;
1032
+
1033
+ if (Object.keys(body).length === 0 && aliasChange === undefined && emailEnabledChange === undefined) {
1025
1034
  console.log(chalk.yellow('No changes specified.'));
1026
1035
  console.log(chalk.gray('Use --help to see available options.'));
1027
1036
  return;
1028
1037
  }
1029
1038
 
1030
1039
  const spinner = ora('Updating agent config...').start();
1031
- log('PATCH /agents/' + agentId, body);
1032
1040
 
1033
1041
  try {
1034
- const res = await fetch(`${API_URL}/agents/${agentId}`, {
1035
- method: 'PATCH',
1036
- headers: {
1037
- 'Content-Type': 'application/json',
1038
- 'X-Session-ID': sessionId,
1039
- },
1040
- body: JSON.stringify(body),
1041
- });
1042
+ if (Object.keys(body).length > 0) {
1043
+ log('PATCH /agents/' + agentId, body);
1044
+ const res = await fetch(`${API_URL}/agents/${agentId}`, {
1045
+ method: 'PATCH',
1046
+ headers: {
1047
+ 'Content-Type': 'application/json',
1048
+ 'X-Session-ID': sessionId,
1049
+ },
1050
+ body: JSON.stringify(body),
1051
+ });
1042
1052
 
1043
- if (!res.ok) {
1044
- const err = await res.json();
1045
- logError('config', err);
1046
- throw new Error(err.error || 'Failed to update agent');
1053
+ if (!res.ok) {
1054
+ const err = await res.json();
1055
+ logError('config', err);
1056
+ throw new Error(err.error || 'Failed to update agent');
1057
+ }
1058
+ }
1059
+
1060
+ // Alias rename has its own endpoint because it also writes the
1061
+ // 30-day grace redirect into agent_alias_history.
1062
+ if (aliasChange !== undefined) {
1063
+ log('PATCH /agents/' + agentId + '/alias', { alias: aliasChange });
1064
+ const res = await fetch(`${API_URL}/agents/${agentId}/alias`, {
1065
+ method: 'PATCH',
1066
+ headers: {
1067
+ 'Content-Type': 'application/json',
1068
+ 'X-Session-ID': sessionId,
1069
+ },
1070
+ body: JSON.stringify({ alias: aliasChange }),
1071
+ });
1072
+ if (!res.ok) {
1073
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
1074
+ logError('alias', err);
1075
+ throw new Error((err as { error?: string }).error || 'Failed to set alias');
1076
+ }
1077
+ }
1078
+
1079
+ // Email toggle is a dedicated endpoint that enforces alias-first.
1080
+ if (emailEnabledChange !== undefined) {
1081
+ log('PATCH /agents/' + agentId + '/email-enabled', { enabled: emailEnabledChange });
1082
+ const res = await fetch(`${API_URL}/agents/${agentId}/email-enabled`, {
1083
+ method: 'PATCH',
1084
+ headers: {
1085
+ 'Content-Type': 'application/json',
1086
+ 'X-Session-ID': sessionId,
1087
+ },
1088
+ body: JSON.stringify({ enabled: emailEnabledChange }),
1089
+ });
1090
+ if (!res.ok) {
1091
+ const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
1092
+ logError('email-enabled', err);
1093
+ throw new Error((err as { error?: string }).error || 'Failed to toggle email');
1094
+ }
1047
1095
  }
1048
1096
 
1049
1097
  spinner.succeed('Agent config updated');
@@ -1073,6 +1121,12 @@ ${chalk.bold('Examples:')}
1073
1121
  const desc = body.description as string;
1074
1122
  changes.push(` Description: ${chalk.gray(desc.slice(0, 50))}${desc.length > 50 ? '...' : ''}`);
1075
1123
  }
1124
+ if (aliasChange !== undefined) {
1125
+ changes.push(` Alias: ${brand.green(aliasChange)}`);
1126
+ }
1127
+ if (emailEnabledChange !== undefined) {
1128
+ changes.push(` Email: ${emailEnabledChange ? brand.green('enabled 📬') : chalk.gray('disabled')}`);
1129
+ }
1076
1130
 
1077
1131
  if (changes.length > 0) {
1078
1132
  console.log('');