@agentuity/cli 0.1.32 → 0.1.33

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 (68) hide show
  1. package/dist/cmd/cloud/deploy.d.ts.map +1 -1
  2. package/dist/cmd/cloud/deploy.js +52 -2
  3. package/dist/cmd/cloud/deploy.js.map +1 -1
  4. package/dist/cmd/cloud/env/delete.d.ts.map +1 -1
  5. package/dist/cmd/cloud/env/delete.js +3 -4
  6. package/dist/cmd/cloud/env/delete.js.map +1 -1
  7. package/dist/cmd/cloud/env/import.d.ts.map +1 -1
  8. package/dist/cmd/cloud/env/import.js +4 -6
  9. package/dist/cmd/cloud/env/import.js.map +1 -1
  10. package/dist/cmd/cloud/env/pull.d.ts.map +1 -1
  11. package/dist/cmd/cloud/env/pull.js +17 -25
  12. package/dist/cmd/cloud/env/pull.js.map +1 -1
  13. package/dist/cmd/cloud/env/set.d.ts.map +1 -1
  14. package/dist/cmd/cloud/env/set.js +3 -6
  15. package/dist/cmd/cloud/env/set.js.map +1 -1
  16. package/dist/cmd/cloud/region-lookup.d.ts +2 -2
  17. package/dist/cmd/cloud/region-lookup.d.ts.map +1 -1
  18. package/dist/cmd/cloud/region-lookup.js +7 -3
  19. package/dist/cmd/cloud/region-lookup.js.map +1 -1
  20. package/dist/cmd/cloud/scp/download.d.ts.map +1 -1
  21. package/dist/cmd/cloud/scp/download.js +1 -1
  22. package/dist/cmd/cloud/scp/download.js.map +1 -1
  23. package/dist/cmd/cloud/scp/upload.d.ts.map +1 -1
  24. package/dist/cmd/cloud/scp/upload.js +1 -1
  25. package/dist/cmd/cloud/scp/upload.js.map +1 -1
  26. package/dist/cmd/cloud/ssh.d.ts.map +1 -1
  27. package/dist/cmd/cloud/ssh.js +1 -1
  28. package/dist/cmd/cloud/ssh.js.map +1 -1
  29. package/dist/cmd/cloud/storage/create.d.ts.map +1 -1
  30. package/dist/cmd/cloud/storage/create.js +7 -2
  31. package/dist/cmd/cloud/storage/create.js.map +1 -1
  32. package/dist/cmd/cloud/storage/get.d.ts.map +1 -1
  33. package/dist/cmd/cloud/storage/get.js +6 -0
  34. package/dist/cmd/cloud/storage/get.js.map +1 -1
  35. package/dist/cmd/cloud/storage/list.d.ts.map +1 -1
  36. package/dist/cmd/cloud/storage/list.js +6 -0
  37. package/dist/cmd/cloud/storage/list.js.map +1 -1
  38. package/dist/cmd/project/auth/init.d.ts.map +1 -1
  39. package/dist/cmd/project/auth/init.js +10 -21
  40. package/dist/cmd/project/auth/init.js.map +1 -1
  41. package/dist/config.d.ts +2 -1
  42. package/dist/config.d.ts.map +1 -1
  43. package/dist/config.js +7 -2
  44. package/dist/config.js.map +1 -1
  45. package/dist/env-util.d.ts +8 -1
  46. package/dist/env-util.d.ts.map +1 -1
  47. package/dist/env-util.js +12 -3
  48. package/dist/env-util.js.map +1 -1
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/types.js +4 -1
  51. package/dist/types.js.map +1 -1
  52. package/package.json +6 -6
  53. package/src/cmd/cloud/deploy.ts +71 -1
  54. package/src/cmd/cloud/env/delete.ts +2 -4
  55. package/src/cmd/cloud/env/import.ts +3 -8
  56. package/src/cmd/cloud/env/pull.ts +17 -26
  57. package/src/cmd/cloud/env/set.ts +2 -8
  58. package/src/cmd/cloud/region-lookup.ts +19 -4
  59. package/src/cmd/cloud/scp/download.ts +2 -1
  60. package/src/cmd/cloud/scp/upload.ts +2 -1
  61. package/src/cmd/cloud/ssh.ts +2 -1
  62. package/src/cmd/cloud/storage/create.ts +7 -2
  63. package/src/cmd/cloud/storage/get.ts +6 -0
  64. package/src/cmd/cloud/storage/list.ts +6 -0
  65. package/src/cmd/project/auth/init.ts +10 -22
  66. package/src/config.ts +10 -2
  67. package/src/env-util.ts +20 -3
  68. package/src/types.ts +4 -1
@@ -12,6 +12,7 @@ import {
12
12
  generateAuthSchemaSql,
13
13
  getGeneratedSqlDir,
14
14
  } from './shared';
15
+ import { readEnvFile, writeEnvFile } from '../../../env-util';
15
16
  import enquirer from 'enquirer';
16
17
  import * as fs from 'fs';
17
18
  import * as path from 'path';
@@ -96,32 +97,23 @@ export const initSubcommand = createSubcommand({
96
97
 
97
98
  const databaseName = dbInfo.name;
98
99
 
99
- // Update .env with database URL
100
+ // Update .env with database URL using proper parsing
100
101
  const envPath = path.join(projectDir, '.env');
101
- let envContent = '';
102
-
103
- if (fs.existsSync(envPath)) {
104
- envContent = fs.readFileSync(envPath, 'utf-8');
105
- if (!envContent.endsWith('\n') && envContent.length > 0) {
106
- envContent += '\n';
107
- }
108
- }
102
+ const existingEnv = await readEnvFile(envPath);
109
103
 
110
104
  // Check if DATABASE_URL already exists
111
- const hasDatabaseUrl = envContent.match(/^DATABASE_URL=/m);
105
+ const hasDatabaseUrl = 'DATABASE_URL' in existingEnv;
112
106
 
113
107
  if (dbInfo.url !== databaseUrl || !hasDatabaseUrl) {
114
108
  if (hasDatabaseUrl) {
115
109
  // DATABASE_URL exists, use AUTH_DATABASE_URL instead
116
- envContent += `AUTH_DATABASE_URL="${dbInfo.url}"\n`;
117
- fs.writeFileSync(envPath, envContent);
110
+ await writeEnvFile(envPath, { AUTH_DATABASE_URL: dbInfo.url });
118
111
  tui.success('AUTH_DATABASE_URL added to .env');
119
112
  tui.warning(
120
113
  `DATABASE_URL already exists. Update your ${tui.bold('src/auth.ts')} to use AUTH_DATABASE_URL.`
121
114
  );
122
115
  } else {
123
- envContent += `DATABASE_URL="${dbInfo.url}"\n`;
124
- fs.writeFileSync(envPath, envContent);
116
+ await writeEnvFile(envPath, { DATABASE_URL: dbInfo.url });
125
117
  tui.success('DATABASE_URL added to .env');
126
118
  }
127
119
  } else {
@@ -129,18 +121,14 @@ export const initSubcommand = createSubcommand({
129
121
  }
130
122
 
131
123
  // Add AGENTUITY_AUTH_SECRET if not present
132
- // Re-read envContent to get latest state
133
- envContent = fs.existsSync(envPath) ? fs.readFileSync(envPath, 'utf-8') : '';
134
- if (!envContent.endsWith('\n') && envContent.length > 0) {
135
- envContent += '\n';
136
- }
124
+ // Re-read env to get latest state
125
+ const currentEnv = await readEnvFile(envPath);
137
126
 
138
127
  const hasAuthSecret =
139
- envContent.match(/^AGENTUITY_AUTH_SECRET=/m) || envContent.match(/^BETTER_AUTH_SECRET=/m);
128
+ 'AGENTUITY_AUTH_SECRET' in currentEnv || 'BETTER_AUTH_SECRET' in currentEnv;
140
129
  if (!hasAuthSecret) {
141
130
  const devSecret = `dev-${crypto.randomUUID()}-CHANGE-ME`;
142
- envContent += `AGENTUITY_AUTH_SECRET="${devSecret}"\n`;
143
- fs.writeFileSync(envPath, envContent);
131
+ await writeEnvFile(envPath, { AGENTUITY_AUTH_SECRET: devSecret });
144
132
  tui.success('AGENTUITY_AUTH_SECRET added to .env (development default)');
145
133
  tui.warning(
146
134
  `Replace ${tui.bold('AGENTUITY_AUTH_SECRET')} with a secure value before deploying.`
package/src/config.ts CHANGED
@@ -809,14 +809,16 @@ export async function getDefaultRegion(
809
809
  * @param auth - Authentication data
810
810
  * @param profileName - Profile name (default: 'production')
811
811
  * @param orgId - Optional organization ID for CLI key authentication
812
+ * @param config - Optional config for region preference lookup
812
813
  */
813
814
  export async function getGlobalCatalystAPIClient(
814
815
  logger: Logger,
815
816
  auth: AuthData,
816
817
  profileName = 'production',
817
- orgId?: string
818
+ orgId?: string,
819
+ config?: Config | null
818
820
  ) {
819
- const region = await getDefaultRegion(profileName);
821
+ const region = await getDefaultRegion(profileName, config);
820
822
  return getCatalystAPIClient(logger, auth, region, orgId);
821
823
  }
822
824
 
@@ -828,6 +830,12 @@ export function getIONHost(config: Config | null, region: string) {
828
830
  if (config?.name === 'local' || region === 'local') {
829
831
  return 'ion.agentuity.io';
830
832
  }
833
+ // Validate region is a non-empty string to prevent malformed hostnames
834
+ if (!region || typeof region !== 'string' || region.trim() === '') {
835
+ throw new Error(
836
+ `Invalid region: '${region}'. Region must be a non-empty string. Use --region flag to specify a valid region.`
837
+ );
838
+ }
831
839
  return `ion-${region}.agentuity.cloud`;
832
840
  }
833
841
 
package/src/env-util.ts CHANGED
@@ -149,7 +149,8 @@ export async function readEnvFile(path: string): Promise<EnvVars> {
149
149
 
150
150
  /**
151
151
  * Write environment variables to an .env file
152
- * Optionally skip certain keys (like AGENTUITY_SDK_KEY)
152
+ * By default, preserves existing keys that are not in the new vars.
153
+ * Use preserveExisting: false to completely overwrite the file.
153
154
  */
154
155
  export async function writeEnvFile(
155
156
  path: string,
@@ -157,20 +158,36 @@ export async function writeEnvFile(
157
158
  options?: {
158
159
  skipKeys?: string[];
159
160
  addComment?: (key: string) => string | null;
161
+ /**
162
+ * When true (default), reads existing file first and merges with new vars.
163
+ * New vars take priority for matching keys, but all existing keys are preserved.
164
+ * When false, completely overwrites the file with only the provided vars.
165
+ */
166
+ preserveExisting?: boolean;
160
167
  }
161
168
  ): Promise<void> {
162
169
  const skipKeys = options?.skipKeys || [];
170
+ const preserveExisting = options?.preserveExisting ?? true;
171
+
172
+ // If preserveExisting is true, read existing file and merge
173
+ let finalVars = vars;
174
+ if (preserveExisting) {
175
+ const existing = await readEnvFile(path);
176
+ // Merge: existing as base, new vars override
177
+ finalVars = { ...existing, ...vars };
178
+ }
179
+
163
180
  const lines: string[] = [];
164
181
 
165
182
  // Sort keys for consistent output
166
- const sortedKeys = Object.keys(vars).sort();
183
+ const sortedKeys = Object.keys(finalVars).sort();
167
184
 
168
185
  for (const key of sortedKeys) {
169
186
  if (skipKeys.includes(key)) {
170
187
  continue;
171
188
  }
172
189
 
173
- const value = vars[key];
190
+ const value = finalVars[key];
174
191
 
175
192
  // Add comment if provided
176
193
  if (options?.addComment) {
package/src/types.ts CHANGED
@@ -24,7 +24,10 @@ export const ConfigSchema = zod.object({
24
24
  devmode: zod
25
25
  .object({
26
26
  hostname: zod.string().optional().describe('Development mode hostname'),
27
- privateKey: zod.string().optional().describe('Development mode private key (base64-encoded PEM)'),
27
+ privateKey: zod
28
+ .string()
29
+ .optional()
30
+ .describe('Development mode private key (base64-encoded PEM)'),
28
31
  })
29
32
  .optional()
30
33
  .describe('Development mode configuration'),