@agentuity/cli 1.0.14 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-detection.js +2 -2
- package/dist/agent-detection.js.map +1 -1
- package/dist/banner.js +2 -2
- package/dist/banner.js.map +1 -1
- package/dist/bun-path.d.ts.map +1 -1
- package/dist/bun-path.js +2 -1
- package/dist/bun-path.js.map +1 -1
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +87 -14
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/entry-generator.d.ts.map +1 -1
- package/dist/cmd/build/entry-generator.js +5 -2
- package/dist/cmd/build/entry-generator.js.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/agent-discovery.js +3 -2
- package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/metadata-generator.js +3 -38
- package/dist/cmd/build/vite/metadata-generator.js.map +1 -1
- package/dist/cmd/build/vite/registry-generator.d.ts.map +1 -1
- package/dist/cmd/build/vite/registry-generator.js +24 -9
- package/dist/cmd/build/vite/registry-generator.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js +3 -2
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js +1 -1
- package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-asset-server.js +42 -39
- package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +19 -21
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/cloud/env/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/env/delete.js +3 -26
- package/dist/cmd/cloud/env/delete.js.map +1 -1
- package/dist/cmd/cloud/env/import.d.ts.map +1 -1
- package/dist/cmd/cloud/env/import.js +3 -16
- package/dist/cmd/cloud/env/import.js.map +1 -1
- package/dist/cmd/cloud/env/set.d.ts.map +1 -1
- package/dist/cmd/cloud/env/set.js +3 -19
- package/dist/cmd/cloud/env/set.js.map +1 -1
- package/dist/cmd/cloud/sandbox/cp.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/cp.js +2 -1
- package/dist/cmd/cloud/sandbox/cp.js.map +1 -1
- package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/get.js +5 -0
- package/dist/cmd/cloud/sandbox/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/build.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/build.js +32 -1
- package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/generate.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/generate.js +7 -0
- package/dist/cmd/cloud/sandbox/snapshot/generate.js.map +1 -1
- package/dist/cmd/cloud/storage/create.d.ts.map +1 -1
- package/dist/cmd/cloud/storage/create.js +58 -26
- package/dist/cmd/cloud/storage/create.js.map +1 -1
- package/dist/cmd/cloud/storage/delete.d.ts.map +1 -1
- package/dist/cmd/cloud/storage/delete.js +108 -16
- package/dist/cmd/cloud/storage/delete.js.map +1 -1
- package/dist/cmd/git/account/add.d.ts +6 -8
- package/dist/cmd/git/account/add.d.ts.map +1 -1
- package/dist/cmd/git/account/add.js +37 -151
- package/dist/cmd/git/account/add.js.map +1 -1
- package/dist/cmd/git/account/index.d.ts +0 -1
- package/dist/cmd/git/account/index.d.ts.map +1 -1
- package/dist/cmd/git/account/index.js +3 -4
- package/dist/cmd/git/account/index.js.map +1 -1
- package/dist/cmd/git/account/list.d.ts.map +1 -1
- package/dist/cmd/git/account/list.js +35 -67
- package/dist/cmd/git/account/list.js.map +1 -1
- package/dist/cmd/git/account/remove.d.ts.map +1 -1
- package/dist/cmd/git/account/remove.js +42 -84
- package/dist/cmd/git/account/remove.js.map +1 -1
- package/dist/cmd/git/api.d.ts +19 -23
- package/dist/cmd/git/api.d.ts.map +1 -1
- package/dist/cmd/git/api.js +38 -56
- package/dist/cmd/git/api.js.map +1 -1
- package/dist/cmd/git/identity/connect.d.ts +15 -0
- package/dist/cmd/git/identity/connect.d.ts.map +1 -0
- package/dist/cmd/git/identity/connect.js +135 -0
- package/dist/cmd/git/identity/connect.js.map +1 -0
- package/dist/cmd/git/identity/disconnect.d.ts +2 -0
- package/dist/cmd/git/identity/disconnect.d.ts.map +1 -0
- package/dist/cmd/git/identity/disconnect.js +83 -0
- package/dist/cmd/git/identity/disconnect.js.map +1 -0
- package/dist/cmd/git/identity/index.d.ts +2 -0
- package/dist/cmd/git/identity/index.d.ts.map +1 -0
- package/dist/cmd/git/identity/index.js +10 -0
- package/dist/cmd/git/identity/index.js.map +1 -0
- package/dist/cmd/git/identity/status.d.ts +2 -0
- package/dist/cmd/git/identity/status.d.ts.map +1 -0
- package/dist/cmd/git/identity/status.js +77 -0
- package/dist/cmd/git/identity/status.js.map +1 -0
- package/dist/cmd/git/index.d.ts +0 -1
- package/dist/cmd/git/index.d.ts.map +1 -1
- package/dist/cmd/git/index.js +3 -2
- package/dist/cmd/git/index.js.map +1 -1
- package/dist/cmd/git/link.d.ts +2 -3
- package/dist/cmd/git/link.d.ts.map +1 -1
- package/dist/cmd/git/link.js +22 -28
- package/dist/cmd/git/link.js.map +1 -1
- package/dist/cmd/git/list.d.ts.map +1 -1
- package/dist/cmd/git/list.js +42 -55
- package/dist/cmd/git/list.js.map +1 -1
- package/dist/cmd/git/status.d.ts.map +1 -1
- package/dist/cmd/git/status.js +51 -38
- package/dist/cmd/git/status.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -4
- package/dist/config.js.map +1 -1
- package/dist/utils/detectSubagent.d.ts.map +1 -1
- package/dist/utils/detectSubagent.js +3 -0
- package/dist/utils/detectSubagent.js.map +1 -1
- package/dist/utils/normalize-path.d.ts +11 -0
- package/dist/utils/normalize-path.d.ts.map +1 -0
- package/dist/utils/normalize-path.js +13 -0
- package/dist/utils/normalize-path.js.map +1 -0
- package/dist/utils/zip.d.ts.map +1 -1
- package/dist/utils/zip.js +2 -1
- package/dist/utils/zip.js.map +1 -1
- package/package.json +6 -6
- package/src/agent-detection.ts +2 -2
- package/src/banner.ts +2 -2
- package/src/bun-path.ts +2 -1
- package/src/cmd/build/ast.ts +96 -15
- package/src/cmd/build/entry-generator.ts +6 -2
- package/src/cmd/build/vite/agent-discovery.ts +3 -2
- package/src/cmd/build/vite/metadata-generator.ts +3 -40
- package/src/cmd/build/vite/registry-generator.ts +26 -9
- package/src/cmd/build/vite/route-discovery.ts +3 -2
- package/src/cmd/build/vite/vite-asset-server-config.ts +1 -1
- package/src/cmd/build/vite/vite-asset-server.ts +53 -40
- package/src/cmd/cloud/deploy.ts +54 -61
- package/src/cmd/cloud/env/delete.ts +3 -34
- package/src/cmd/cloud/env/import.ts +2 -18
- package/src/cmd/cloud/env/set.ts +2 -21
- package/src/cmd/cloud/sandbox/cp.ts +2 -1
- package/src/cmd/cloud/sandbox/get.ts +5 -0
- package/src/cmd/cloud/sandbox/snapshot/build.ts +41 -0
- package/src/cmd/cloud/sandbox/snapshot/generate.ts +7 -0
- package/src/cmd/cloud/storage/create.ts +62 -27
- package/src/cmd/cloud/storage/delete.ts +136 -17
- package/src/cmd/git/account/add.ts +51 -190
- package/src/cmd/git/account/index.ts +3 -5
- package/src/cmd/git/account/list.ts +51 -82
- package/src/cmd/git/account/remove.ts +45 -95
- package/src/cmd/git/api.ts +49 -111
- package/src/cmd/git/identity/connect.ts +178 -0
- package/src/cmd/git/identity/disconnect.ts +103 -0
- package/src/cmd/git/identity/index.ts +10 -0
- package/src/cmd/git/identity/status.ts +96 -0
- package/src/cmd/git/index.ts +3 -3
- package/src/cmd/git/link.ts +32 -35
- package/src/cmd/git/list.ts +48 -59
- package/src/cmd/git/status.ts +55 -40
- package/src/config.ts +14 -5
- package/src/utils/detectSubagent.ts +5 -0
- package/src/utils/normalize-path.ts +12 -0
- package/src/utils/zip.ts +2 -1
|
@@ -9,6 +9,7 @@ import { writeFileSync, mkdirSync, existsSync, unlinkSync, readFileSync } from '
|
|
|
9
9
|
import { stat } from 'node:fs/promises';
|
|
10
10
|
import { StructuredError } from '@agentuity/core';
|
|
11
11
|
import { toCamelCase, toPascalCase } from '../../../utils/string';
|
|
12
|
+
import { toForwardSlash } from '../../../utils/normalize-path';
|
|
12
13
|
import type { AgentMetadata } from './agent-discovery';
|
|
13
14
|
import type { RouteInfo } from './route-discovery';
|
|
14
15
|
|
|
@@ -27,7 +28,7 @@ function rebaseImportPath(routeFilename: string, schemaImportPath: string, srcDi
|
|
|
27
28
|
|
|
28
29
|
// Normalize route filename to get its directory relative to srcDir
|
|
29
30
|
let routeDir: string;
|
|
30
|
-
const cleanFilename = routeFilename
|
|
31
|
+
const cleanFilename = toForwardSlash(routeFilename);
|
|
31
32
|
if (cleanFilename.startsWith('./')) {
|
|
32
33
|
routeDir = dirname(join(srcDir, cleanFilename.substring(2)));
|
|
33
34
|
} else if (cleanFilename.startsWith('src/')) {
|
|
@@ -41,7 +42,7 @@ function rebaseImportPath(routeFilename: string, schemaImportPath: string, srcDi
|
|
|
41
42
|
|
|
42
43
|
// Calculate the relative path from src/generated/ to the resolved schema path
|
|
43
44
|
const generatedDir = join(srcDir, 'generated');
|
|
44
|
-
let rebasedPath = relative(generatedDir, resolvedSchemaPath)
|
|
45
|
+
let rebasedPath = toForwardSlash(relative(generatedDir, resolvedSchemaPath));
|
|
45
46
|
|
|
46
47
|
// Ensure it starts with './' or '../'
|
|
47
48
|
if (!rebasedPath.startsWith('.') && !rebasedPath.startsWith('/')) {
|
|
@@ -69,6 +70,21 @@ function sanitizePathSegment(segment: string): string {
|
|
|
69
70
|
return toCamelCase(segment.replace(ROUTE_PARAM_CHARS, ''));
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Valid unquoted TypeScript/JavaScript property name pattern.
|
|
75
|
+
* A property name can be unquoted if it starts with a letter, underscore, or dollar sign,
|
|
76
|
+
* and contains only letters, digits, underscores, or dollar signs.
|
|
77
|
+
*/
|
|
78
|
+
const VALID_UNQUOTED_PROPERTY = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Quote a property name for TypeScript object type definitions if it contains
|
|
82
|
+
* characters that require quoting (e.g., dots, hyphens, spaces).
|
|
83
|
+
*/
|
|
84
|
+
function quotePropertyName(name: string): string {
|
|
85
|
+
return VALID_UNQUOTED_PROPERTY.test(name) ? name : JSON.stringify(name);
|
|
86
|
+
}
|
|
87
|
+
|
|
72
88
|
/**
|
|
73
89
|
* Generate TypeScript type for path parameters.
|
|
74
90
|
* Returns 'never' if no path params, or '{ param1: string; param2: string }' format.
|
|
@@ -136,7 +152,7 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
|
|
|
136
152
|
if (evalMeta.filename === agent.filename) continue;
|
|
137
153
|
|
|
138
154
|
// Build the relative path for the eval file
|
|
139
|
-
let evalRelativePath = evalMeta.filename;
|
|
155
|
+
let evalRelativePath = toForwardSlash(evalMeta.filename);
|
|
140
156
|
if (evalRelativePath.startsWith('./agent/')) {
|
|
141
157
|
evalRelativePath = evalRelativePath
|
|
142
158
|
.replace(/^\.\/agent\//, '../agent/')
|
|
@@ -165,7 +181,7 @@ export function generateAgentRegistry(srcDir: string, agents: AgentMetadata[]):
|
|
|
165
181
|
.map(({ name, filename }) => {
|
|
166
182
|
const camelName = toCamelCase(name);
|
|
167
183
|
// Handle both './agent/...' and 'src/agent/...' formats
|
|
168
|
-
let relativePath = filename;
|
|
184
|
+
let relativePath = toForwardSlash(filename);
|
|
169
185
|
if (relativePath.startsWith('./agent/')) {
|
|
170
186
|
// ./agent/foo.ts -> ../agent/foo.js (use .js extension for TypeScript)
|
|
171
187
|
relativePath = relativePath
|
|
@@ -478,11 +494,11 @@ function generateRPCRegistryType(
|
|
|
478
494
|
const pathParamsType = generatePathParamsType(routeInfo.pathParams);
|
|
479
495
|
const pathParamsTupleType = generatePathParamsTupleType(routeInfo.pathParams);
|
|
480
496
|
lines.push(
|
|
481
|
-
`${indent}${key}: { input: ${value.input}; output: ${value.output}; type: ${value.type}; params: ${pathParamsType}; paramsTuple: ${pathParamsTupleType} };`
|
|
497
|
+
`${indent}${quotePropertyName(key)}: { input: ${value.input}; output: ${value.output}; type: ${value.type}; params: ${pathParamsType}; paramsTuple: ${pathParamsTupleType} };`
|
|
482
498
|
);
|
|
483
499
|
} else {
|
|
484
500
|
// Nested node
|
|
485
|
-
lines.push(`${indent}${key}: {`);
|
|
501
|
+
lines.push(`${indent}${quotePropertyName(key)}: {`);
|
|
486
502
|
lines.push(treeToTypeString(value as NestedNode, indent + '\t'));
|
|
487
503
|
lines.push(`${indent}};`);
|
|
488
504
|
}
|
|
@@ -716,7 +732,8 @@ export async function generateRouteRegistry(
|
|
|
716
732
|
resolvedPath = `../api/${finalPath}`;
|
|
717
733
|
} else if (resolvedPath.startsWith('./') || resolvedPath.startsWith('../')) {
|
|
718
734
|
// Resolve relative import from route file's directory
|
|
719
|
-
const
|
|
735
|
+
const normalizedFilename = toForwardSlash(route.filename);
|
|
736
|
+
const routeDir = normalizedFilename.substring(0, normalizedFilename.lastIndexOf('/'));
|
|
720
737
|
// Join and normalize the path
|
|
721
738
|
const joined = `${routeDir}/${resolvedPath}`;
|
|
722
739
|
// Normalize by resolving .. and . segments
|
|
@@ -784,7 +801,7 @@ export async function generateRouteRegistry(
|
|
|
784
801
|
: (route.inputSchemaImportedName ?? route.inputSchemaVariable);
|
|
785
802
|
} else {
|
|
786
803
|
// Schema is locally defined - import from the route file
|
|
787
|
-
const filename = route.filename
|
|
804
|
+
const filename = toForwardSlash(route.filename);
|
|
788
805
|
const withoutSrc = filename.startsWith('src/') ? filename.substring(4) : filename;
|
|
789
806
|
const withoutLeadingDot = withoutSrc.startsWith('./')
|
|
790
807
|
? withoutSrc.substring(2)
|
|
@@ -819,7 +836,7 @@ export async function generateRouteRegistry(
|
|
|
819
836
|
: (route.outputSchemaImportedName ?? route.outputSchemaVariable);
|
|
820
837
|
} else {
|
|
821
838
|
// Schema is locally defined - import from the route file
|
|
822
|
-
const filename = route.filename
|
|
839
|
+
const filename = toForwardSlash(route.filename);
|
|
823
840
|
const withoutSrc = filename.startsWith('src/') ? filename.substring(4) : filename;
|
|
824
841
|
const withoutLeadingDot = withoutSrc.startsWith('./')
|
|
825
842
|
? withoutSrc.substring(2)
|
|
@@ -9,6 +9,7 @@ import { join, relative } from 'node:path';
|
|
|
9
9
|
import { existsSync } from 'node:fs';
|
|
10
10
|
import type { Logger } from '../../../types';
|
|
11
11
|
import { parseRoute } from '../ast';
|
|
12
|
+
import { toForwardSlash } from '../../../utils/normalize-path';
|
|
12
13
|
|
|
13
14
|
export interface RouteMetadata {
|
|
14
15
|
id: string;
|
|
@@ -105,7 +106,7 @@ export async function discoverRoutes(
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
const rootDir = join(srcDir, '..');
|
|
108
|
-
const relativeFilename = './' + relative(srcDir, filePath);
|
|
109
|
+
const relativeFilename = './' + toForwardSlash(relative(srcDir, filePath));
|
|
109
110
|
|
|
110
111
|
try {
|
|
111
112
|
const parsedRoutes = await parseRoute(
|
|
@@ -183,7 +184,7 @@ export async function discoverRoutes(
|
|
|
183
184
|
const rootDir = join(srcDir, '..');
|
|
184
185
|
const subrouterRelPaths = new Set<string>();
|
|
185
186
|
for (const absPath of mountedSubrouters) {
|
|
186
|
-
subrouterRelPaths.add(relative(rootDir, absPath));
|
|
187
|
+
subrouterRelPaths.add(toForwardSlash(relative(rootDir, absPath)));
|
|
187
188
|
}
|
|
188
189
|
|
|
189
190
|
// Remove routes whose filename matches a sub-router file
|
|
@@ -92,7 +92,7 @@ export async function generateAssetServerConfig(
|
|
|
92
92
|
server: {
|
|
93
93
|
// Use the port we selected
|
|
94
94
|
port,
|
|
95
|
-
strictPort:
|
|
95
|
+
strictPort: true, // Port is pre-verified as available by findAvailablePort()
|
|
96
96
|
host: '127.0.0.1',
|
|
97
97
|
|
|
98
98
|
// CORS headers to allow Bun server on port 3500 to proxy requests
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { join } from 'node:path';
|
|
9
9
|
import { createRequire } from 'node:module';
|
|
10
|
+
import { createServer as createNetServer } from 'node:net';
|
|
10
11
|
import type { ViteDevServer } from 'vite';
|
|
11
12
|
import type { Logger } from '../../../types';
|
|
12
13
|
import { generateAssetServerConfig } from './vite-asset-server-config';
|
|
@@ -22,6 +23,44 @@ export interface StartViteAssetServerOptions {
|
|
|
22
23
|
workbenchPath?: string;
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Check if a specific port is available on the given host.
|
|
28
|
+
*/
|
|
29
|
+
function isPortAvailable(port: number, host: string): Promise<boolean> {
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
const server = createNetServer();
|
|
32
|
+
server.once('error', () => {
|
|
33
|
+
resolve(false);
|
|
34
|
+
});
|
|
35
|
+
server.listen(port, host, () => {
|
|
36
|
+
server.close(() => {
|
|
37
|
+
resolve(true);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Find an available port starting from the preferred port.
|
|
45
|
+
* Tries incrementing ports up to maxAttempts times.
|
|
46
|
+
*/
|
|
47
|
+
async function findAvailablePort(
|
|
48
|
+
preferredPort: number,
|
|
49
|
+
host: string = '127.0.0.1',
|
|
50
|
+
maxAttempts: number = 20
|
|
51
|
+
): Promise<number> {
|
|
52
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
53
|
+
const port = preferredPort + attempt;
|
|
54
|
+
const available = await isPortAvailable(port, host);
|
|
55
|
+
if (available) {
|
|
56
|
+
return port;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
throw new Error(
|
|
60
|
+
`Could not find an available port after ${maxAttempts} attempts starting from ${preferredPort}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
25
64
|
/**
|
|
26
65
|
* Start Vite asset server on a dynamically-chosen port
|
|
27
66
|
* Returns the server instance and the actual port number
|
|
@@ -33,16 +72,23 @@ export async function startViteAssetServer(
|
|
|
33
72
|
|
|
34
73
|
logger.debug('Starting Vite asset server (HMR only)...');
|
|
35
74
|
|
|
36
|
-
//
|
|
37
|
-
//
|
|
75
|
+
// Find an available port before starting Vite
|
|
76
|
+
// This avoids relying on Vite's strictPort:false fallback which can fail
|
|
38
77
|
const preferredPort = 5173;
|
|
78
|
+
const availablePort = await findAvailablePort(preferredPort, '127.0.0.1');
|
|
39
79
|
|
|
40
|
-
|
|
80
|
+
if (availablePort !== preferredPort) {
|
|
81
|
+
logger.info(
|
|
82
|
+
`Port ${preferredPort} is in use, using port ${availablePort} for Vite asset server`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Generate minimal config with the available port
|
|
41
87
|
const config = await generateAssetServerConfig({
|
|
42
88
|
rootDir,
|
|
43
89
|
logger,
|
|
44
90
|
workbenchPath,
|
|
45
|
-
port:
|
|
91
|
+
port: availablePort,
|
|
46
92
|
});
|
|
47
93
|
|
|
48
94
|
// Dynamically import vite from the project's node_modules
|
|
@@ -54,7 +100,6 @@ export async function startViteAssetServer(
|
|
|
54
100
|
const server = await createServer(config);
|
|
55
101
|
|
|
56
102
|
// Start listening with timeout to prevent hangs
|
|
57
|
-
// Vite will choose alternate port if preferred is taken
|
|
58
103
|
const STARTUP_TIMEOUT_MS = 30000; // 30 seconds
|
|
59
104
|
|
|
60
105
|
try {
|
|
@@ -82,42 +127,10 @@ export async function startViteAssetServer(
|
|
|
82
127
|
throw error;
|
|
83
128
|
}
|
|
84
129
|
|
|
85
|
-
//
|
|
86
|
-
const
|
|
87
|
-
const httpServer = server.httpServer;
|
|
88
|
-
if (httpServer) {
|
|
89
|
-
const address = httpServer.address();
|
|
90
|
-
if (address && typeof address === 'object' && 'port' in address) {
|
|
91
|
-
return address.port;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// Get the actual port Vite is using from the httpServer
|
|
98
|
-
// server.config.server.port is the requested port, not the actual one
|
|
99
|
-
let actualPort = preferredPort;
|
|
100
|
-
|
|
101
|
-
// The resolved URL contains the actual port being used
|
|
102
|
-
const resolvedUrls = server.resolvedUrls;
|
|
103
|
-
if (resolvedUrls?.local && resolvedUrls.local.length > 0) {
|
|
104
|
-
try {
|
|
105
|
-
const url = new URL(resolvedUrls.local[0]);
|
|
106
|
-
actualPort = parseInt(url.port, 10) || preferredPort;
|
|
107
|
-
} catch {
|
|
108
|
-
actualPort = getPortFromHttpServer() ?? preferredPort;
|
|
109
|
-
}
|
|
110
|
-
} else {
|
|
111
|
-
actualPort = getPortFromHttpServer() ?? preferredPort;
|
|
112
|
-
}
|
|
130
|
+
// Port was pre-verified and strictPort:true ensures Vite uses exactly this port
|
|
131
|
+
const actualPort = availablePort;
|
|
113
132
|
|
|
114
|
-
|
|
115
|
-
logger.info(`Vite asset server running on port ${actualPort}`);
|
|
116
|
-
} else {
|
|
117
|
-
logger.warn(
|
|
118
|
-
`Vite asset server running on port ${actualPort} (preferred port ${preferredPort} was in use)`
|
|
119
|
-
);
|
|
120
|
-
}
|
|
133
|
+
logger.info(`Vite asset server running on port ${actualPort}`);
|
|
121
134
|
logger.debug(`Asset server will handle: HMR, React transformation, source maps`);
|
|
122
135
|
logger.debug(
|
|
123
136
|
`HMR WebSocket configured at /__vite_hmr (proxied through Bun server for tunnel support)`
|
package/src/cmd/cloud/deploy.ts
CHANGED
|
@@ -1,68 +1,69 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { join, resolve } from 'node:path';
|
|
3
1
|
import { createPublicKey } from 'node:crypto';
|
|
4
2
|
import { createReadStream, createWriteStream, existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
5
3
|
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
6
5
|
import { StructuredError } from '@agentuity/core';
|
|
7
|
-
import { createSubcommand, DeployOptionsSchema } from '../../types';
|
|
8
|
-
import { getUserAgent } from '../../api';
|
|
9
|
-
import * as tui from '../../tui';
|
|
10
|
-
import {
|
|
11
|
-
saveProjectDir,
|
|
12
|
-
getDefaultConfigDir,
|
|
13
|
-
loadProjectSDKKey,
|
|
14
|
-
updateProjectConfig,
|
|
15
|
-
getGlobalCatalystAPIClient,
|
|
16
|
-
} from '../../config';
|
|
17
|
-
import { getProjectGithubStatus } from '../git/api';
|
|
18
|
-
import { runGitLink } from '../git/link';
|
|
19
6
|
import {
|
|
20
|
-
runSteps,
|
|
21
|
-
stepSuccess,
|
|
22
|
-
stepSkipped,
|
|
23
|
-
stepError,
|
|
24
|
-
pauseStepUI,
|
|
25
|
-
StepInterruptError,
|
|
26
|
-
type Step,
|
|
27
|
-
type StepContext,
|
|
28
|
-
} from '../../steps';
|
|
29
|
-
import { viteBundle } from '../build/vite-bundler';
|
|
30
|
-
import { loadBuildMetadata, getStreamURL } from '../../config';
|
|
31
|
-
import {
|
|
32
|
-
projectEnvUpdate,
|
|
33
|
-
projectDeploymentCreate,
|
|
34
|
-
projectDeploymentUpdate,
|
|
35
|
-
projectDeploymentComplete,
|
|
36
|
-
projectDeploymentStatus,
|
|
37
|
-
projectDeploymentMalwareCheck,
|
|
38
|
-
validateResources,
|
|
39
|
-
projectGet,
|
|
40
|
-
projectUpdateRegion,
|
|
41
|
-
type Deployment,
|
|
42
7
|
type BuildMetadata,
|
|
43
|
-
type
|
|
8
|
+
type Deployment,
|
|
44
9
|
type DeploymentComplete,
|
|
10
|
+
type DeploymentInstructions,
|
|
45
11
|
type DeploymentStatusResult,
|
|
46
|
-
type MalwareCheckResult,
|
|
47
12
|
getAppBaseURL,
|
|
13
|
+
type MalwareCheckResult,
|
|
14
|
+
projectDeploymentComplete,
|
|
15
|
+
projectDeploymentCreate,
|
|
16
|
+
projectDeploymentMalwareCheck,
|
|
17
|
+
projectDeploymentStatus,
|
|
18
|
+
projectDeploymentUpdate,
|
|
19
|
+
projectEnvUpdate,
|
|
20
|
+
projectGet,
|
|
21
|
+
projectUpdateRegion,
|
|
22
|
+
validateResources,
|
|
48
23
|
} from '@agentuity/server';
|
|
24
|
+
import { z } from 'zod';
|
|
25
|
+
import { getUserAgent } from '../../api';
|
|
26
|
+
import { BuildReportCollector, clearGlobalCollector, setGlobalCollector } from '../../build-report';
|
|
27
|
+
import { getCachedProject, setCachedProject } from '../../cache';
|
|
28
|
+
import { getCommand } from '../../command-prefix';
|
|
49
29
|
import {
|
|
30
|
+
getDefaultConfigDir,
|
|
31
|
+
getGlobalCatalystAPIClient,
|
|
32
|
+
getStreamURL,
|
|
33
|
+
loadBuildMetadata,
|
|
34
|
+
loadProjectSDKKey,
|
|
35
|
+
saveProjectDir,
|
|
36
|
+
updateProjectConfig,
|
|
37
|
+
} from '../../config';
|
|
38
|
+
import { encryptFIPSKEMDEMStream } from '../../crypto/box';
|
|
39
|
+
import * as domain from '../../domain';
|
|
40
|
+
import {
|
|
41
|
+
filterAgentuitySdkKeys,
|
|
50
42
|
findExistingEnvFile,
|
|
51
43
|
readEnvFile,
|
|
52
|
-
filterAgentuitySdkKeys,
|
|
53
44
|
splitEnvAndSecrets,
|
|
54
45
|
} from '../../env-util';
|
|
55
|
-
import { zipDir } from '../../utils/zip';
|
|
56
|
-
import { encryptFIPSKEMDEMStream } from '../../crypto/box';
|
|
57
|
-
import { getCommand } from '../../command-prefix';
|
|
58
|
-
import * as domain from '../../domain';
|
|
59
46
|
import { ErrorCode, getExitCode } from '../../errors';
|
|
60
|
-
import {
|
|
61
|
-
|
|
62
|
-
|
|
47
|
+
import {
|
|
48
|
+
pauseStepUI,
|
|
49
|
+
runSteps,
|
|
50
|
+
type Step,
|
|
51
|
+
type StepContext,
|
|
52
|
+
StepInterruptError,
|
|
53
|
+
stepError,
|
|
54
|
+
stepSkipped,
|
|
55
|
+
stepSuccess,
|
|
56
|
+
} from '../../steps';
|
|
57
|
+
import * as tui from '../../tui';
|
|
58
|
+
import { createSubcommand, DeployOptionsSchema } from '../../types';
|
|
63
59
|
import { validateAptDependencies } from '../../utils/apt-validator';
|
|
64
60
|
import { extractDependencies } from '../../utils/deps';
|
|
65
|
-
import {
|
|
61
|
+
import { zipDir } from '../../utils/zip';
|
|
62
|
+
import { typecheck } from '../build/typecheck';
|
|
63
|
+
import { viteBundle } from '../build/vite-bundler';
|
|
64
|
+
import { getProjectGithubStatus } from '../git/api';
|
|
65
|
+
import { runGitLink } from '../git/link';
|
|
66
|
+
import { runForkedDeploy } from './deploy-fork';
|
|
66
67
|
|
|
67
68
|
const DeploymentCancelledError = StructuredError(
|
|
68
69
|
'DeploymentCancelled',
|
|
@@ -501,7 +502,6 @@ export const deploySubcommand = createSubcommand({
|
|
|
501
502
|
const result = await runGitLink({
|
|
502
503
|
apiClient,
|
|
503
504
|
projectId: project.projectId,
|
|
504
|
-
orgId: project.orgId,
|
|
505
505
|
logger,
|
|
506
506
|
skipAlreadyLinkedCheck: true,
|
|
507
507
|
config,
|
|
@@ -515,7 +515,8 @@ export const deploySubcommand = createSubcommand({
|
|
|
515
515
|
tui.info('Push a commit to trigger your first deployment.');
|
|
516
516
|
tui.newline();
|
|
517
517
|
throw new DeploymentCancelledError();
|
|
518
|
-
}
|
|
518
|
+
}
|
|
519
|
+
if (result.linked) {
|
|
519
520
|
// Linked but auto-deploy disabled, continue with manual deploy
|
|
520
521
|
tui.newline();
|
|
521
522
|
tui.info('GitHub repository linked. Continuing with deployment...');
|
|
@@ -623,9 +624,7 @@ export const deploySubcommand = createSubcommand({
|
|
|
623
624
|
|
|
624
625
|
if (typeResult.success) {
|
|
625
626
|
capturedOutput.push(
|
|
626
|
-
tui.muted(
|
|
627
|
-
`✓ Typechecked in ${Math.floor(Date.now() - started).toFixed(0)}ms`
|
|
628
|
-
)
|
|
627
|
+
tui.muted(`✓ Typechecked in ${Date.now() - started}ms`)
|
|
629
628
|
);
|
|
630
629
|
} else {
|
|
631
630
|
// Errors already added to collector by typecheck()
|
|
@@ -1174,9 +1173,7 @@ export const deploySubcommand = createSubcommand({
|
|
|
1174
1173
|
|
|
1175
1174
|
const lines = [`${ex}`, ''];
|
|
1176
1175
|
lines.push(
|
|
1177
|
-
`${tui.ICONS.arrow} ${
|
|
1178
|
-
tui.bold(tui.padRight('Dashboard:', 12)) + tui.link(dashboard)
|
|
1179
|
-
}`
|
|
1176
|
+
`${tui.ICONS.arrow} ${tui.bold(tui.padRight('Dashboard:', 12)) + tui.link(dashboard)}`
|
|
1180
1177
|
);
|
|
1181
1178
|
tui.banner(tui.colorError(`Deployment: ${deployment.id} Failed`), lines.join('\n'), {
|
|
1182
1179
|
centerTitle: false,
|
|
@@ -1209,15 +1206,11 @@ export const deploySubcommand = createSubcommand({
|
|
|
1209
1206
|
}`
|
|
1210
1207
|
);
|
|
1211
1208
|
lines.push(
|
|
1212
|
-
`${tui.ICONS.arrow} ${
|
|
1213
|
-
tui.bold(tui.padRight('Project:', 12)) + tui.link(latestUrl)
|
|
1214
|
-
}`
|
|
1209
|
+
`${tui.ICONS.arrow} ${tui.bold(tui.padRight('Project:', 12)) + tui.link(latestUrl)}`
|
|
1215
1210
|
);
|
|
1216
1211
|
}
|
|
1217
1212
|
lines.push(
|
|
1218
|
-
`${tui.ICONS.arrow} ${
|
|
1219
|
-
tui.bold(tui.padRight('Dashboard:', 12)) + tui.link(dashboard)
|
|
1220
|
-
}`
|
|
1213
|
+
`${tui.ICONS.arrow} ${tui.bold(tui.padRight('Dashboard:', 12)) + tui.link(dashboard)}`
|
|
1221
1214
|
);
|
|
1222
1215
|
tui.banner(`Deployment: ${tui.colorPrimary(deployment.id)}`, lines.join('\n'), {
|
|
1223
1216
|
centerTitle: false,
|
|
@@ -2,12 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { createSubcommand } from '../../../types';
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
4
|
import { projectEnvDelete, projectGet, orgEnvDelete, orgEnvGet } from '@agentuity/server';
|
|
5
|
-
import {
|
|
6
|
-
findExistingEnvFile,
|
|
7
|
-
readEnvFile,
|
|
8
|
-
writeEnvFile,
|
|
9
|
-
isReservedAgentuityKey,
|
|
10
|
-
} from '../../../env-util';
|
|
5
|
+
import { isReservedAgentuityKey } from '../../../env-util';
|
|
11
6
|
import { getCommand } from '../../../command-prefix';
|
|
12
7
|
import { ErrorCode } from '../../../errors';
|
|
13
8
|
import { resolveOrgId, isOrgScope } from './org-util';
|
|
@@ -15,10 +10,6 @@ import { resolveOrgId, isOrgScope } from './org-util';
|
|
|
15
10
|
const EnvDeleteResponseSchema = z.object({
|
|
16
11
|
success: z.boolean().describe('Whether the operation succeeded'),
|
|
17
12
|
keys: z.array(z.string()).describe('Variable keys that were deleted'),
|
|
18
|
-
path: z
|
|
19
|
-
.string()
|
|
20
|
-
.optional()
|
|
21
|
-
.describe('Local file path where variables were removed (project scope only)'),
|
|
22
13
|
secrets: z.array(z.string()).describe('Keys that were secrets'),
|
|
23
14
|
env: z.array(z.string()).describe('Keys that were environment variables'),
|
|
24
15
|
scope: z.enum(['project', 'org']).describe('The scope from which the variables were deleted'),
|
|
@@ -61,7 +52,7 @@ export const deleteSubcommand = createSubcommand({
|
|
|
61
52
|
},
|
|
62
53
|
|
|
63
54
|
async handler(ctx) {
|
|
64
|
-
const { args, project,
|
|
55
|
+
const { args, project, apiClient, config, opts } = ctx;
|
|
65
56
|
const useOrgScope = isOrgScope(opts?.org);
|
|
66
57
|
const keys = args.key;
|
|
67
58
|
|
|
@@ -174,38 +165,16 @@ export const deleteSubcommand = createSubcommand({
|
|
|
174
165
|
});
|
|
175
166
|
});
|
|
176
167
|
|
|
177
|
-
// Update local .env file only if we have a project directory and an existing .env file
|
|
178
|
-
let envFilePath: string | undefined;
|
|
179
|
-
if (projectDir) {
|
|
180
|
-
envFilePath = await findExistingEnvFile(projectDir);
|
|
181
|
-
if (envFilePath) {
|
|
182
|
-
const currentEnv = await readEnvFile(envFilePath);
|
|
183
|
-
const originalKeyCount = Object.keys(currentEnv).length;
|
|
184
|
-
for (const key of [...secretKeys, ...envKeys]) {
|
|
185
|
-
delete currentEnv[key];
|
|
186
|
-
}
|
|
187
|
-
// Only write if we actually removed keys (avoid creating empty file)
|
|
188
|
-
const keysRemoved = originalKeyCount > Object.keys(currentEnv).length;
|
|
189
|
-
if (keysRemoved) {
|
|
190
|
-
await writeEnvFile(envFilePath, currentEnv, { preserveExisting: false });
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
168
|
const deletedKeys = [...secretKeys, ...envKeys];
|
|
196
169
|
if (notFoundKeys.length > 0) {
|
|
197
170
|
tui.warning(`Variables not found (skipped): ${notFoundKeys.join(', ')}`);
|
|
198
171
|
}
|
|
199
172
|
|
|
200
|
-
|
|
201
|
-
tui.success(
|
|
202
|
-
`Deleted ${deletedKeys.length} variable(s): ${deletedKeys.join(', ')}${locationMsg}`
|
|
203
|
-
);
|
|
173
|
+
tui.success(`Deleted ${deletedKeys.length} variable(s): ${deletedKeys.join(', ')}`);
|
|
204
174
|
|
|
205
175
|
return {
|
|
206
176
|
success: true,
|
|
207
177
|
keys: deletedKeys,
|
|
208
|
-
path: envFilePath,
|
|
209
178
|
secrets: secretKeys,
|
|
210
179
|
env: envKeys,
|
|
211
180
|
scope: 'project' as const,
|
|
@@ -3,9 +3,7 @@ import { createSubcommand } from '../../../types';
|
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
4
|
import { projectEnvUpdate, orgEnvUpdate } from '@agentuity/server';
|
|
5
5
|
import {
|
|
6
|
-
findExistingEnvFile,
|
|
7
6
|
readEnvFile,
|
|
8
|
-
writeEnvFile,
|
|
9
7
|
filterAgentuitySdkKeys,
|
|
10
8
|
splitEnvAndSecrets,
|
|
11
9
|
validateNoPublicSecrets,
|
|
@@ -19,17 +17,13 @@ const EnvImportResponseSchema = z.object({
|
|
|
19
17
|
envCount: z.number().describe('Number of env vars imported'),
|
|
20
18
|
secretCount: z.number().describe('Number of secrets imported'),
|
|
21
19
|
skipped: z.number().describe('Number of items skipped'),
|
|
22
|
-
path: z
|
|
23
|
-
.string()
|
|
24
|
-
.optional()
|
|
25
|
-
.describe('Local file path where variables were saved (project scope only)'),
|
|
26
20
|
file: z.string().describe('Source file path'),
|
|
27
21
|
scope: z.enum(['project', 'org']).describe('The scope where variables were imported'),
|
|
28
22
|
});
|
|
29
23
|
|
|
30
24
|
export const importSubcommand = createSubcommand({
|
|
31
25
|
name: 'import',
|
|
32
|
-
description: 'Import environment variables and secrets from a file to cloud
|
|
26
|
+
description: 'Import environment variables and secrets from a file to cloud',
|
|
33
27
|
tags: ['mutating', 'creates-resource', 'slow', 'api-intensive', 'requires-auth'],
|
|
34
28
|
examples: [
|
|
35
29
|
{
|
|
@@ -62,7 +56,7 @@ export const importSubcommand = createSubcommand({
|
|
|
62
56
|
},
|
|
63
57
|
|
|
64
58
|
async handler(ctx) {
|
|
65
|
-
const { args, apiClient, project,
|
|
59
|
+
const { args, apiClient, project, config, opts } = ctx;
|
|
66
60
|
const useOrgScope = isOrgScope(opts?.org);
|
|
67
61
|
|
|
68
62
|
// Require project context if not using org scope
|
|
@@ -161,15 +155,6 @@ export const importSubcommand = createSubcommand({
|
|
|
161
155
|
});
|
|
162
156
|
});
|
|
163
157
|
|
|
164
|
-
// Merge with local .env file only if we have a project directory
|
|
165
|
-
let localEnvPath: string | undefined;
|
|
166
|
-
if (projectDir) {
|
|
167
|
-
localEnvPath = await findExistingEnvFile(projectDir);
|
|
168
|
-
// writeEnvFile preserves existing keys by default, so just write the filtered vars
|
|
169
|
-
// This will merge with existing .env content, preserving AGENTUITY_SDK_KEY and other keys
|
|
170
|
-
await writeEnvFile(localEnvPath, filteredVars);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
158
|
tui.success(
|
|
174
159
|
`Imported ${totalCount} variable${totalCount !== 1 ? 's' : ''} from ${args.file} (${envCount} env, ${secretCount} secret${secretCount !== 1 ? 's' : ''})`
|
|
175
160
|
);
|
|
@@ -180,7 +165,6 @@ export const importSubcommand = createSubcommand({
|
|
|
180
165
|
envCount,
|
|
181
166
|
secretCount,
|
|
182
167
|
skipped: Object.keys(importedVars).length - totalCount,
|
|
183
|
-
path: localEnvPath,
|
|
184
168
|
file: args.file,
|
|
185
169
|
scope: 'project' as const,
|
|
186
170
|
};
|
package/src/cmd/cloud/env/set.ts
CHANGED
|
@@ -3,8 +3,6 @@ import { createSubcommand } from '../../../types';
|
|
|
3
3
|
import * as tui from '../../../tui';
|
|
4
4
|
import { projectEnvUpdate, orgEnvUpdate } from '@agentuity/server';
|
|
5
5
|
import {
|
|
6
|
-
findExistingEnvFile,
|
|
7
|
-
writeEnvFile,
|
|
8
6
|
looksLikeSecret,
|
|
9
7
|
isReservedAgentuityKey,
|
|
10
8
|
isPublicVarKey,
|
|
@@ -75,10 +73,6 @@ function parseEnvArgs(rawArgs: string[]): ParsedEnvPair[] {
|
|
|
75
73
|
const EnvSetResponseSchema = z.object({
|
|
76
74
|
success: z.boolean().describe('Whether the operation succeeded'),
|
|
77
75
|
keys: z.array(z.string()).describe('Environment variable keys that were set'),
|
|
78
|
-
path: z
|
|
79
|
-
.string()
|
|
80
|
-
.optional()
|
|
81
|
-
.describe('Local file path where env vars were saved (project scope only)'),
|
|
82
76
|
secretKeys: z.array(z.string()).describe('Keys that were stored as secrets'),
|
|
83
77
|
envKeys: z.array(z.string()).describe('Keys that were stored as env vars'),
|
|
84
78
|
scope: z.enum(['project', 'org']).describe('The scope where the variables were set'),
|
|
@@ -134,7 +128,7 @@ export const setSubcommand = createSubcommand({
|
|
|
134
128
|
},
|
|
135
129
|
|
|
136
130
|
async handler(ctx) {
|
|
137
|
-
const { args: cmdArgs, opts, apiClient, project,
|
|
131
|
+
const { args: cmdArgs, opts, apiClient, project, config } = ctx;
|
|
138
132
|
const useOrgScope = isOrgScope(opts?.org);
|
|
139
133
|
const forceSecret = opts?.secret ?? false;
|
|
140
134
|
|
|
@@ -262,26 +256,13 @@ export const setSubcommand = createSubcommand({
|
|
|
262
256
|
}
|
|
263
257
|
);
|
|
264
258
|
|
|
265
|
-
// Update local .env file only if we have a project directory
|
|
266
|
-
let envFilePath: string | undefined;
|
|
267
|
-
if (projectDir) {
|
|
268
|
-
envFilePath = await findExistingEnvFile(projectDir);
|
|
269
|
-
const allPairsForLocal: Record<string, string> = {
|
|
270
|
-
...envPairs,
|
|
271
|
-
...secretPairs,
|
|
272
|
-
};
|
|
273
|
-
await writeEnvFile(envFilePath, allPairsForLocal);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const locationMsg = envFilePath ? ` (cloud + ${envFilePath})` : ' (cloud only)';
|
|
277
259
|
tui.success(
|
|
278
|
-
`Variable${totalCount !== 1 ? 's' : ''} set successfully: ${allKeys.join(', ')}${secretSuffix}
|
|
260
|
+
`Variable${totalCount !== 1 ? 's' : ''} set successfully: ${allKeys.join(', ')}${secretSuffix}`
|
|
279
261
|
);
|
|
280
262
|
|
|
281
263
|
return {
|
|
282
264
|
success: true,
|
|
283
265
|
keys: allKeys,
|
|
284
|
-
path: envFilePath,
|
|
285
266
|
secretKeys: secretKeysList,
|
|
286
267
|
envKeys: envKeysList,
|
|
287
268
|
scope: 'project' as const,
|
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { readFileSync, writeFileSync, mkdirSync, statSync, readdirSync } from 'node:fs';
|
|
3
3
|
import { dirname, resolve, basename, join, relative } from 'node:path';
|
|
4
4
|
import { createCommand } from '../../../types';
|
|
5
|
+
import { toForwardSlash } from '../../../utils/normalize-path';
|
|
5
6
|
import * as tui from '../../../tui';
|
|
6
7
|
import { createSandboxClient } from './util';
|
|
7
8
|
import { getCommand } from '../../../command-prefix';
|
|
@@ -265,7 +266,7 @@ async function uploadDirectory(
|
|
|
265
266
|
: effectiveRemotePath;
|
|
266
267
|
|
|
267
268
|
for (const filePath of allFiles) {
|
|
268
|
-
const relativePath = relative(localDir, filePath);
|
|
269
|
+
const relativePath = toForwardSlash(relative(localDir, filePath));
|
|
269
270
|
const targetPath = `${baseRemotePath}/${relativePath}`;
|
|
270
271
|
const buffer = readFileSync(filePath);
|
|
271
272
|
files.push({ path: targetPath, content: buffer });
|