forked from aws/agentcore-cli
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathnode.ts
More file actions
141 lines (118 loc) · 4.69 KB
/
Copy pathnode.ts
File metadata and controls
141 lines (118 loc) · 4.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import type { AgentEnvSpec, NodeRuntime, RuntimeVersion } from '../../schema';
import { NPM_INSTALL_HINT, getArtifactZipName } from '../constants';
import { runSubprocessCapture, runSubprocessCaptureSync } from '../utils/subprocess';
import { PackagingError } from './errors';
import {
copySourceTree,
copySourceTreeSync,
createZipFromDir,
createZipFromDirSync,
enforceZipSizeLimit,
enforceZipSizeLimitSync,
ensureBinaryAvailable,
ensureBinaryAvailableSync,
ensureDirClean,
ensureDirCleanSync,
isNodeRuntime,
resolveProjectPaths,
resolveProjectPathsSync,
} from './helpers';
import type { ArtifactResult, CodeZipPackager, PackageOptions, RuntimePackager } from './types/packaging';
import { join } from 'path';
const NODE_RUNTIME_REGEX = /NODE_(\d+)/;
/**
* Type guard to check if runtime version is a Node runtime
*/
function isNodeRuntimeVersion(version: RuntimeVersion): version is NodeRuntime {
return isNodeRuntime(version);
}
/**
* Extracts Node version from runtime constant.
* Example: NODE_20 -> "20" (for use with node version checks)
*/
export function extractNodeVersion(runtime: NodeRuntime): string {
const match = NODE_RUNTIME_REGEX.exec(runtime);
if (!match) {
throw new PackagingError(`Unsupported Node runtime value: ${runtime}`);
}
const [, major] = match;
if (!major) {
throw new PackagingError(`Invalid Node runtime value: ${runtime}`);
}
return major;
}
/**
* Async Node/TypeScript packager for CLI usage.
*/
export class NodeCodeZipPackager implements RuntimePackager {
async pack(spec: AgentEnvSpec, options: PackageOptions = {}): Promise<ArtifactResult> {
if (spec.build !== 'CodeZip') {
throw new PackagingError('Node packager only supports CodeZip build type.');
}
if (!isNodeRuntimeVersion(spec.runtimeVersion!)) {
throw new PackagingError(`Node packager only supports Node runtimes. Received: ${spec.runtimeVersion}`);
}
const agentName = options.agentName ?? spec.name;
const { projectRoot, srcDir, stagingDir, artifactsDir } = await resolveProjectPaths(options, agentName);
await ensureBinaryAvailable('npm', NPM_INSTALL_HINT);
await ensureDirClean(stagingDir);
// Copy source files
await copySourceTree(srcDir, stagingDir);
// Install production dependencies
await this.installDependencies(projectRoot, stagingDir);
const artifactPath = options.outputPath ?? join(artifactsDir, getArtifactZipName(agentName));
await createZipFromDir(stagingDir, artifactPath);
const sizeBytes = await enforceZipSizeLimit(artifactPath);
return {
artifactPath,
sizeBytes,
stagingPath: stagingDir,
};
}
private async installDependencies(projectRoot: string, stagingDir: string): Promise<void> {
// Copy package.json to staging
const result = await runSubprocessCapture('npm', ['install', '--omit=dev', '--prefix', stagingDir], {
cwd: projectRoot,
});
if (result.code !== 0) {
const combined = `${result.stdout}\n${result.stderr}`.trim();
throw new PackagingError(combined.length > 0 ? combined : `npm install failed with exit code ${result.code}`);
}
}
}
/**
* Sync Node/TypeScript packager for CDK bundling.
*/
export class NodeCodeZipPackagerSync implements CodeZipPackager {
packCodeZip(config: AgentEnvSpec, options: PackageOptions = {}): ArtifactResult {
const runtimeVersion = config.runtimeVersion ?? 'NODE_20';
if (!isNodeRuntimeVersion(runtimeVersion)) {
throw new PackagingError(`Node packager only supports Node runtimes. Received: ${runtimeVersion}`);
}
const agentName = options.agentName ?? config.name ?? 'asset';
const { projectRoot, srcDir, stagingDir, artifactsDir } = resolveProjectPathsSync(options, agentName);
ensureBinaryAvailableSync('npm', NPM_INSTALL_HINT);
ensureDirCleanSync(stagingDir);
// Copy source files
copySourceTreeSync(srcDir, stagingDir);
// Install production dependencies
this.installDependenciesSync(projectRoot, stagingDir);
const artifactPath = options.outputPath ?? join(artifactsDir, getArtifactZipName(agentName));
createZipFromDirSync(stagingDir, artifactPath);
const sizeBytes = enforceZipSizeLimitSync(artifactPath);
return {
artifactPath,
sizeBytes,
stagingPath: stagingDir,
};
}
private installDependenciesSync(projectRoot: string, stagingDir: string): void {
const result = runSubprocessCaptureSync('npm', ['install', '--omit=dev', '--prefix', stagingDir], {
cwd: projectRoot,
});
if (result.code !== 0) {
const combined = `${result.stdout}\n${result.stderr}`.trim();
throw new PackagingError(combined.length > 0 ? combined : `npm install failed with exit code ${result.code}`);
}
}
}