@aws/nx-plugin 1.0.0-rc.55 → 1.0.0-rc.57
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/migrations.json +13 -3
- package/package.json +1 -1
- package/src/migrations/latest/dynamodb-local-remove-optimize-flag/migration.d.ts +6 -0
- package/src/migrations/latest/dynamodb-local-remove-optimize-flag/migration.js +89 -0
- package/src/migrations/latest/dynamodb-local-remove-optimize-flag/migration.js.map +1 -0
- package/src/migrations/latest/modernize-function-props-cast/migration.js +0 -1
- package/src/migrations/latest/modernize-function-props-cast/migration.js.map +1 -1
- package/src/migrations/latest/order-access-log-delivery-after-bucket-policy/migration.js +0 -1
- package/src/migrations/latest/order-access-log-delivery-after-bucket-policy/migration.js.map +1 -1
- package/src/migrations/latest/restrict-cors-to-custom-domains/migration.js +0 -2
- package/src/migrations/latest/restrict-cors-to-custom-domains/migration.js.map +1 -1
- package/src/migrations/latest/terraform-bootstrap-adopt-existing-bucket/migration.js +0 -1
- package/src/migrations/latest/terraform-bootstrap-adopt-existing-bucket/migration.js.map +1 -1
- package/src/migrations/latest/ts-agent-session-management-support/migration.d.ts +6 -0
- package/src/migrations/latest/ts-agent-session-management-support/migration.js +449 -0
- package/src/migrations/latest/ts-agent-session-management-support/migration.js.map +1 -0
- package/src/migrations/latest/user-identity-waf-allow-localhost-callback/migration.js +0 -2
- package/src/migrations/latest/user-identity-waf-allow-localhost-callback/migration.js.map +1 -1
- package/src/py/agent/__snapshots__/generator.constructs.spec.ts.snap +3 -1
- package/src/py/agent/__snapshots__/generator.frameworks.spec.ts.snap +12 -12
- package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +1 -1
- package/src/py/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -1
- package/src/py/agent/a2a-connection/files/agent-connection/app/__targetAgentSnakeCase___client_strands.py.template +2 -1
- package/src/py/agent/a2a-connection/files/langchain/agent-connection/app/__targetAgentSnakeCase___client_langchain.py.template +2 -1
- package/src/py/agent/generator.js +4 -0
- package/src/py/agent/generator.js.map +1 -1
- package/src/py/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -1
- package/src/py/agent/mcp-connection/files/agent-connection/app/__mcpServerSnakeCase___client_strands.py.template +2 -1
- package/src/py/agent/mcp-connection/files/langchain/agent-connection/app/__mcpServerSnakeCase___client_langchain.py.template +2 -1
- package/src/py/agent/react-connection/__snapshots__/generator.spec.ts.snap +6 -0
- package/src/py/agent/schema.d.js.map +1 -1
- package/src/py/agent/schema.d.ts +3 -0
- package/src/py/agent/schema.json +8 -0
- package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +0 -2
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +4 -2
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +663 -19
- package/src/ts/agent/a2a-connection/__snapshots__/generator.spec.ts.snap +2 -1
- package/src/ts/agent/a2a-connection/files/agent-connection/app/__targetAgentKebabCase__-client-strands.ts.template +1 -1
- package/src/ts/agent/files/ag-ui/index.ts.template +10 -1
- package/src/ts/agent/files/common/agent.ts.template +11 -3
- package/src/ts/agent/files/common/session.ts.template +43 -0
- package/src/ts/agent/gateway-connection/__snapshots__/generator.spec.ts.snap +1 -0
- package/src/ts/agent/generator.d.ts +4 -0
- package/src/ts/agent/generator.js +21 -0
- package/src/ts/agent/generator.js.map +1 -1
- package/src/ts/agent/mcp-connection/__snapshots__/generator.spec.ts.snap +2 -1
- package/src/ts/agent/mcp-connection/files/agent-connection/app/__mcpServerKebabCase__-client-strands.ts.template +2 -1
- package/src/ts/agent/react-connection/__snapshots__/generator.spec.ts.snap +8 -4
- package/src/ts/agent/react-connection/files/src/components/__agentNameClassName__AgentClientProvider.tsx.template +2 -1
- package/src/ts/agent/schema.d.js.map +1 -1
- package/src/ts/agent/schema.d.ts +3 -0
- package/src/ts/agent/schema.json +8 -0
- package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +0 -2
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +4 -2
- package/src/ts/nx-migration/files/migration.ts.template +4 -0
- package/src/utils/agent-chat/files/common/agentcore.ts.template +2 -2
- package/src/utils/agent-connection/agent-connection.js +4 -0
- package/src/utils/agent-connection/agent-connection.js.map +1 -1
- package/src/utils/agent-connection/files/core-runtime-config/runtime-config.ts.template +11 -1
- package/src/utils/agent-connection/files/core-strands/base/model-errors-strands.ts.template +26 -15
- package/src/utils/agent-connection/files/core-strands/base/tool-errors-strands.ts.template +23 -16
- package/src/utils/agent-connection/files/py-core-runtime-config/runtime_config.py.template +4 -3
- package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +4 -0
- package/src/utils/agent-core-constructs/agent-core-constructs.js +7 -1
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +131 -3
- package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +180 -1
- package/src/utils/ast.d.ts +5 -0
- package/src/utils/ast.js +25 -0
- package/src/utils/ast.js.map +1 -1
- package/src/utils/connection/open-api/files/components/__apiNameClassName__Provider.tsx.template +2 -0
- package/src/utils/files/common/scripts/src/dynamodb/start-container.ts.template +0 -1
- package/src/utils/migration-versions.d.ts +15 -10
- package/src/utils/migration-versions.js +48 -36
- package/src/utils/migration-versions.js.map +1 -1
- package/src/utils/version-upgrade-migration/nx-package-updates.d.ts +18 -8
- package/src/utils/version-upgrade-migration/nx-package-updates.js +19 -11
- package/src/utils/version-upgrade-migration/nx-package-updates.js.map +1 -1
- package/src/utils/version-upgrade-migration/register.d.ts +6 -1
- package/src/utils/version-upgrade-migration/register.js +8 -3
- package/src/utils/version-upgrade-migration/register.js.map +1 -1
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
import { Fn, Lazy, Names
|
|
1
|
+
import { Fn, Lazy, Names<%_ if (session === 's3') { _%>, RemovalPolicy<%_ } _%>, Stack } from 'aws-cdk-lib';
|
|
2
2
|
import { Platform } from 'aws-cdk-lib/aws-ecr-assets';
|
|
3
3
|
import { Connections, IConnectable } from 'aws-cdk-lib/aws-ec2';
|
|
4
|
+
<%_ if (session === 's3') { _%>
|
|
5
|
+
import { BlockPublicAccess, Bucket, BucketEncryption } from 'aws-cdk-lib/aws-s3';
|
|
6
|
+
import { Key } from 'aws-cdk-lib/aws-kms';
|
|
7
|
+
import {
|
|
8
|
+
CfnDelivery,
|
|
9
|
+
CfnDeliveryDestination,
|
|
10
|
+
CfnDeliverySource,
|
|
11
|
+
LogGroup,
|
|
12
|
+
RetentionDays,
|
|
13
|
+
} from 'aws-cdk-lib/aws-logs';
|
|
14
|
+
<%_ } _%>
|
|
4
15
|
import { Construct } from 'constructs';
|
|
5
16
|
import * as path from 'path';
|
|
6
17
|
import * as url from 'url';
|
|
@@ -13,10 +24,13 @@ import {
|
|
|
13
24
|
RuntimeAuthorizerConfiguration,
|
|
14
25
|
<%_ } _%>
|
|
15
26
|
} from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
16
|
-
import { <%_ if (serverProtocol !== 'mcp') { _%>PolicyStatement, <%_ } _%>IGrantable, IPrincipal<%_ if (auth === 'iam') { _%>, Grant<%_ } _%> } from 'aws-cdk-lib/aws-iam';
|
|
27
|
+
import { <%_ if (serverProtocol !== 'mcp') { _%>PolicyStatement, <%_ } _%><%_ if (session === 's3') { _%>Effect, ServicePrincipal, <%_ } _%>IGrantable, IPrincipal<%_ if (auth === 'iam') { _%>, Grant<%_ } _%> } from 'aws-cdk-lib/aws-iam';
|
|
17
28
|
<%_ if (auth === 'cognito') { _%>
|
|
18
29
|
import { IUserPool, IUserPoolClient } from 'aws-cdk-lib/aws-cognito';
|
|
19
30
|
<%_ } _%>
|
|
31
|
+
<%_ if (session === 's3') { _%>
|
|
32
|
+
import { suppressRules } from '../../../core/checkov<% if (esm) { %>.js<% } %>';
|
|
33
|
+
<%_ } _%>
|
|
20
34
|
import { RuntimeConfig } from '../../../core/runtime-config<% if (esm) { %>.js<% } %>';
|
|
21
35
|
import { findWorkspaceRoot } from '../../../core/workspace<% if (esm) { %>.js<% } %>';
|
|
22
36
|
|
|
@@ -72,6 +86,111 @@ export class <%- nameClassName %> extends Construct implements IGrantable, IConn
|
|
|
72
86
|
<%_ if (auth === 'cognito') { _%>
|
|
73
87
|
const { identity, ...restProps } = props;
|
|
74
88
|
|
|
89
|
+
<%_ } _%>
|
|
90
|
+
<%_ if (session === 's3') { _%>
|
|
91
|
+
const sessionKey = new Key(this, 'SessionKey', {
|
|
92
|
+
enableKeyRotation: true,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Allow CloudWatch Logs to use the session key for server access log delivery.
|
|
96
|
+
const stack = Stack.of(this);
|
|
97
|
+
sessionKey.addToResourcePolicy(
|
|
98
|
+
new PolicyStatement({
|
|
99
|
+
effect: Effect.ALLOW,
|
|
100
|
+
principals: [new ServicePrincipal(`logs.${stack.region}.amazonaws.com`)],
|
|
101
|
+
actions: [
|
|
102
|
+
'kms:Encrypt',
|
|
103
|
+
'kms:Decrypt',
|
|
104
|
+
'kms:ReEncrypt*',
|
|
105
|
+
'kms:GenerateDataKey*',
|
|
106
|
+
'kms:DescribeKey',
|
|
107
|
+
],
|
|
108
|
+
resources: ['*'],
|
|
109
|
+
conditions: {
|
|
110
|
+
ArnLike: {
|
|
111
|
+
'kms:EncryptionContext:aws:logs:arn': `arn:aws:logs:${stack.region}:${stack.account}:log-group:*`,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
const sessionAccessLogs = new LogGroup(this, 'SessionAccessLogs', {
|
|
118
|
+
retention: RetentionDays.ONE_YEAR,
|
|
119
|
+
encryptionKey: sessionKey,
|
|
120
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const sessionBucket = new Bucket(this, 'SessionBucket', {
|
|
124
|
+
enforceSSL: true,
|
|
125
|
+
removalPolicy: RemovalPolicy.RETAIN,
|
|
126
|
+
encryption: BucketEncryption.KMS,
|
|
127
|
+
encryptionKey: sessionKey,
|
|
128
|
+
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
|
|
129
|
+
});
|
|
130
|
+
suppressRules(
|
|
131
|
+
sessionBucket,
|
|
132
|
+
['CKV_AWS_21'],
|
|
133
|
+
'Session data does not need versioning enabled',
|
|
134
|
+
);
|
|
135
|
+
suppressRules(
|
|
136
|
+
sessionBucket,
|
|
137
|
+
['CKV2_AWS_61'],
|
|
138
|
+
'Lifecycle configuration not required for session data',
|
|
139
|
+
);
|
|
140
|
+
suppressRules(
|
|
141
|
+
sessionBucket,
|
|
142
|
+
['CKV_AWS_144'],
|
|
143
|
+
'Cross-region replication not required for session data',
|
|
144
|
+
);
|
|
145
|
+
suppressRules(
|
|
146
|
+
sessionBucket,
|
|
147
|
+
['CKV2_AWS_62'],
|
|
148
|
+
'Event notifications not required for session data',
|
|
149
|
+
);
|
|
150
|
+
suppressRules(
|
|
151
|
+
sessionBucket,
|
|
152
|
+
['CKV_AWS_18'],
|
|
153
|
+
'Server access logs are delivered to CloudWatch Logs',
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const sessionAccessLogsSource: CfnDeliverySource = new CfnDeliverySource(
|
|
157
|
+
this,
|
|
158
|
+
'SessionAccessLogsSource',
|
|
159
|
+
{
|
|
160
|
+
name: Lazy.string({
|
|
161
|
+
produce: () =>
|
|
162
|
+
Names.uniqueResourceName(sessionAccessLogsSource, {
|
|
163
|
+
maxLength: 60,
|
|
164
|
+
}),
|
|
165
|
+
}),
|
|
166
|
+
logType: 'S3_SERVER_ACCESS_LOGS',
|
|
167
|
+
resourceArn: sessionBucket.bucketArn,
|
|
168
|
+
},
|
|
169
|
+
);
|
|
170
|
+
const sessionBucketPolicy = sessionBucket.policy;
|
|
171
|
+
if (sessionBucketPolicy) {
|
|
172
|
+
sessionAccessLogsSource.node.addDependency(sessionBucketPolicy);
|
|
173
|
+
}
|
|
174
|
+
const sessionAccessLogsDestination: CfnDeliveryDestination =
|
|
175
|
+
new CfnDeliveryDestination(this, 'SessionAccessLogsDestination', {
|
|
176
|
+
name: Lazy.string({
|
|
177
|
+
produce: () =>
|
|
178
|
+
Names.uniqueResourceName(sessionAccessLogsDestination, {
|
|
179
|
+
maxLength: 60,
|
|
180
|
+
}),
|
|
181
|
+
}),
|
|
182
|
+
destinationResourceArn: sessionAccessLogs.logGroupArn,
|
|
183
|
+
});
|
|
184
|
+
const sessionAccessLogsDelivery = new CfnDelivery(
|
|
185
|
+
this,
|
|
186
|
+
'SessionAccessLogsDelivery',
|
|
187
|
+
{
|
|
188
|
+
deliverySourceName: sessionAccessLogsSource.name,
|
|
189
|
+
deliveryDestinationArn: sessionAccessLogsDestination.attrArn,
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
sessionAccessLogsDelivery.addDependency(sessionAccessLogsSource);
|
|
193
|
+
|
|
75
194
|
<%_ } _%>
|
|
76
195
|
this.agentCoreRuntime = new Runtime(this, '<%- nameClassName %>', {
|
|
77
196
|
runtimeName: Lazy.string({
|
|
@@ -114,12 +233,21 @@ export class <%- nameClassName %> extends Construct implements IGrantable, IConn
|
|
|
114
233
|
}),
|
|
115
234
|
);
|
|
116
235
|
|
|
236
|
+
<%_ } _%>
|
|
237
|
+
<%_ if (session === 's3') { _%>
|
|
238
|
+
sessionBucket.grantReadWrite(this.agentCoreRuntime);
|
|
239
|
+
|
|
117
240
|
<%_ } _%>
|
|
118
241
|
rc.grantReadAppConfig(this.agentCoreRuntime);
|
|
119
242
|
|
|
120
243
|
rc.set('agentcore', 'agentRuntimes', {
|
|
121
244
|
...rc.get('agentcore').agentRuntimes,
|
|
122
|
-
<%- nameClassName %>:
|
|
245
|
+
<%- nameClassName %>: {
|
|
246
|
+
arn: this.agentCoreRuntime.agentRuntimeArn,
|
|
247
|
+
<%_ if (session === 's3') { _%>
|
|
248
|
+
session: { bucketName: sessionBucket.bucketName },
|
|
249
|
+
<%_ } _%>
|
|
250
|
+
},
|
|
123
251
|
});
|
|
124
252
|
}
|
|
125
253
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
<%_ if (session === 's3') { _%>
|
|
2
|
+
terraform {
|
|
3
|
+
required_providers {
|
|
4
|
+
random = {
|
|
5
|
+
source = "hashicorp/random"
|
|
6
|
+
version = "<%- randomProviderVersion %>"
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
<%_ } _%>
|
|
1
12
|
variable "env" {
|
|
2
13
|
description = "Environment variables to pass to the agent core runtime"
|
|
3
14
|
type = map(string)
|
|
@@ -60,11 +71,156 @@ variable "user_pool_client_ids" {
|
|
|
60
71
|
type = list(string)
|
|
61
72
|
}
|
|
62
73
|
|
|
74
|
+
<%_ } _%>
|
|
75
|
+
<%_ if (auth === 'cognito' || session === 's3') { _%>
|
|
63
76
|
data "aws_region" "current" {}
|
|
77
|
+
<%_ } _%>
|
|
78
|
+
<%_ if (session === 's3') { _%>
|
|
79
|
+
data "aws_caller_identity" "current" {}
|
|
80
|
+
<%_ } _%>
|
|
81
|
+
<%_ if (auth === 'cognito') { _%>
|
|
64
82
|
|
|
65
83
|
locals {
|
|
66
84
|
aws_region = data.aws_region.current.id
|
|
67
85
|
}
|
|
86
|
+
<%_ } _%>
|
|
87
|
+
<%_ if (session === 's3') { _%>
|
|
88
|
+
|
|
89
|
+
locals {
|
|
90
|
+
# Delivery source/destination names have a 60 character maximum. Truncate
|
|
91
|
+
# the agent name so these stay within the limit.
|
|
92
|
+
session_access_logs_name_prefix = substr("<%= nameKebabCase %>", 0, 30)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
# Uniquifies resource names below so this construct can be deployed more than
|
|
96
|
+
# once (e.g. across stages) within the same account/region.
|
|
97
|
+
resource "random_id" "session_unique_suffix" {
|
|
98
|
+
byte_length = 4
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# KMS key encrypting the session bucket and its server access logs.
|
|
102
|
+
resource "aws_kms_key" "session" {
|
|
103
|
+
description = "KMS key for <%= nameKebabCase %> agent session data"
|
|
104
|
+
enable_key_rotation = true
|
|
105
|
+
deletion_window_in_days = 7
|
|
106
|
+
|
|
107
|
+
policy = jsonencode({
|
|
108
|
+
Version = "2012-10-17"
|
|
109
|
+
Statement = [
|
|
110
|
+
{
|
|
111
|
+
Sid = "EnableIAMUserPermissions"
|
|
112
|
+
Effect = "Allow"
|
|
113
|
+
Principal = { AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" }
|
|
114
|
+
Action = "kms:*"
|
|
115
|
+
Resource = "*"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
Sid = "AllowCloudWatchLogs"
|
|
119
|
+
Effect = "Allow"
|
|
120
|
+
Principal = { Service = "logs.${data.aws_region.current.region}.amazonaws.com" }
|
|
121
|
+
Action = [
|
|
122
|
+
"kms:Encrypt",
|
|
123
|
+
"kms:Decrypt",
|
|
124
|
+
"kms:ReEncrypt*",
|
|
125
|
+
"kms:GenerateDataKey*",
|
|
126
|
+
"kms:DescribeKey"
|
|
127
|
+
]
|
|
128
|
+
Resource = "*"
|
|
129
|
+
Condition = {
|
|
130
|
+
ArnLike = {
|
|
131
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:log-group:*"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
tags = var.tags
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# CloudWatch log group receiving the session bucket's server access logs.
|
|
142
|
+
resource "aws_cloudwatch_log_group" "session_access_logs" {
|
|
143
|
+
name = "/aws/s3/<%= nameKebabCase %>-session-access-logs-${random_id.session_unique_suffix.hex}"
|
|
144
|
+
retention_in_days = 365
|
|
145
|
+
kms_key_id = aws_kms_key.session.arn
|
|
146
|
+
|
|
147
|
+
tags = var.tags
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Bucket storing the agent's session data
|
|
151
|
+
resource "aws_s3_bucket" "session" {
|
|
152
|
+
#checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for session data
|
|
153
|
+
#checkov:skip=CKV_AWS_144:Cross-region replication not required for session data
|
|
154
|
+
#checkov:skip=CKV2_AWS_62:Event notifications not required for session data
|
|
155
|
+
#checkov:skip=CKV_AWS_18:Server access logs are delivered to CloudWatch Logs (see aws_cloudwatch_log_delivery.session)
|
|
156
|
+
#checkov:skip=CKV_AWS_21:Session data does not need versioning enabled
|
|
157
|
+
force_destroy = false
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
resource "aws_s3_bucket_server_side_encryption_configuration" "session" {
|
|
161
|
+
bucket = aws_s3_bucket.session.id
|
|
162
|
+
|
|
163
|
+
rule {
|
|
164
|
+
apply_server_side_encryption_by_default {
|
|
165
|
+
kms_master_key_id = aws_kms_key.session.arn
|
|
166
|
+
sse_algorithm = "aws:kms"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
resource "aws_s3_bucket_public_access_block" "session" {
|
|
172
|
+
bucket = aws_s3_bucket.session.id
|
|
173
|
+
|
|
174
|
+
block_public_acls = true
|
|
175
|
+
block_public_policy = true
|
|
176
|
+
ignore_public_acls = true
|
|
177
|
+
restrict_public_buckets = true
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
resource "aws_s3_bucket_policy" "session" {
|
|
181
|
+
bucket = aws_s3_bucket.session.id
|
|
182
|
+
|
|
183
|
+
policy = jsonencode({
|
|
184
|
+
Version = "2012-10-17"
|
|
185
|
+
Statement = [
|
|
186
|
+
{
|
|
187
|
+
Sid = "DenyInsecureConnections"
|
|
188
|
+
Effect = "Deny"
|
|
189
|
+
Principal = "*"
|
|
190
|
+
Action = "s3:*"
|
|
191
|
+
Resource = [
|
|
192
|
+
aws_s3_bucket.session.arn,
|
|
193
|
+
"${aws_s3_bucket.session.arn}/*"
|
|
194
|
+
]
|
|
195
|
+
Condition = {
|
|
196
|
+
Bool = {
|
|
197
|
+
"aws:SecureTransport" = "false"
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
# Deliver the session bucket's server access logs to CloudWatch Logs.
|
|
206
|
+
resource "aws_cloudwatch_log_delivery_source" "session" {
|
|
207
|
+
name = "${local.session_access_logs_name_prefix}-access-logs-source-${random_id.session_unique_suffix.hex}"
|
|
208
|
+
log_type = "S3_SERVER_ACCESS_LOGS"
|
|
209
|
+
resource_arn = aws_s3_bucket.session.arn
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
resource "aws_cloudwatch_log_delivery_destination" "session" {
|
|
213
|
+
name = "${local.session_access_logs_name_prefix}-access-logs-dest-${random_id.session_unique_suffix.hex}"
|
|
214
|
+
|
|
215
|
+
delivery_destination_configuration {
|
|
216
|
+
destination_resource_arn = aws_cloudwatch_log_group.session_access_logs.arn
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
resource "aws_cloudwatch_log_delivery" "session" {
|
|
221
|
+
delivery_source_name = aws_cloudwatch_log_delivery_source.session.name
|
|
222
|
+
delivery_destination_arn = aws_cloudwatch_log_delivery_destination.session.arn
|
|
223
|
+
}
|
|
68
224
|
|
|
69
225
|
<%_ } _%>
|
|
70
226
|
module "agent_core_runtime" {
|
|
@@ -107,6 +263,29 @@ module "agent_core_runtime" {
|
|
|
107
263
|
"arn:aws:bedrock:*:*:foundation-model/*",
|
|
108
264
|
"arn:aws:bedrock:*:*:inference-profile/*"
|
|
109
265
|
]
|
|
266
|
+
}<% } %><% if (session === 's3') { %>,
|
|
267
|
+
# Grant access for the agent to read/write its session data
|
|
268
|
+
{
|
|
269
|
+
Effect = "Allow"
|
|
270
|
+
Action = [
|
|
271
|
+
"s3:GetObject",
|
|
272
|
+
"s3:PutObject",
|
|
273
|
+
"s3:DeleteObject",
|
|
274
|
+
"s3:ListBucket"
|
|
275
|
+
]
|
|
276
|
+
Resource = [
|
|
277
|
+
aws_s3_bucket.session.arn,
|
|
278
|
+
"${aws_s3_bucket.session.arn}/*"
|
|
279
|
+
]
|
|
280
|
+
},
|
|
281
|
+
# Grant access for the agent to use the session bucket's KMS key
|
|
282
|
+
{
|
|
283
|
+
Effect = "Allow"
|
|
284
|
+
Action = [
|
|
285
|
+
"kms:Decrypt",
|
|
286
|
+
"kms:GenerateDataKey*"
|
|
287
|
+
]
|
|
288
|
+
Resource = [aws_kms_key.session.arn]
|
|
110
289
|
}<% } %>
|
|
111
290
|
], var.additional_iam_policy_statements)
|
|
112
291
|
tags = var.tags
|
|
@@ -118,7 +297,7 @@ module "add_agent_runtime_to_runtime_config" {
|
|
|
118
297
|
|
|
119
298
|
namespace = "agentcore"
|
|
120
299
|
key = "agentRuntimes"
|
|
121
|
-
value = { "<%= nameClassName %>" = module.agent_core_runtime.agent_core_runtime_arn }
|
|
300
|
+
value = { "<%= nameClassName %>" = { arn = module.agent_core_runtime.agent_core_runtime_arn<% if (session === 's3') { %>, session = { bucketName = aws_s3_bucket.session.bucket }<% } %> } }
|
|
122
301
|
|
|
123
302
|
depends_on = [module.agent_core_runtime]
|
|
124
303
|
}
|
package/src/utils/ast.d.ts
CHANGED
|
@@ -54,6 +54,11 @@ export declare const matchGritQL: (tree: Tree, filePath: string, pattern: string
|
|
|
54
54
|
* matches. The file is not modified.
|
|
55
55
|
*/
|
|
56
56
|
export declare const captureGritQL: (tree: Tree, filePath: string, pattern: string) => Promise<string | undefined>;
|
|
57
|
+
/**
|
|
58
|
+
* Like `captureGritQL`, but returns one metavariable's binding (e.g. `mod`
|
|
59
|
+
* for `$mod`) instead of the whole matched node.
|
|
60
|
+
*/
|
|
61
|
+
export declare const captureGritQLVariable: (tree: Tree, filePath: string, pattern: string, variableName: string) => Promise<string | undefined>;
|
|
57
62
|
/**
|
|
58
63
|
* Return the text of every node matching the GritQL pattern, in document order.
|
|
59
64
|
*/
|
package/src/utils/ast.js
CHANGED
|
@@ -226,6 +226,31 @@ export const addDestructuredImport = async (tree, filePath, variableNames, from)
|
|
|
226
226
|
}
|
|
227
227
|
return captured;
|
|
228
228
|
};
|
|
229
|
+
/**
|
|
230
|
+
* Like `captureGritQL`, but returns one metavariable's binding (e.g. `mod`
|
|
231
|
+
* for `$mod`) instead of the whole matched node.
|
|
232
|
+
*/ export const captureGritQLVariable = async (tree, filePath, pattern, variableName)=>{
|
|
233
|
+
if (!tree.exists(filePath)) return undefined;
|
|
234
|
+
ensureGritDir(tree);
|
|
235
|
+
const source = tree.read(filePath).toString();
|
|
236
|
+
// The underlying binding lookup requires the `$` sigil.
|
|
237
|
+
const name = variableName.startsWith('$') ? variableName : `$${variableName}`;
|
|
238
|
+
let captured;
|
|
239
|
+
try {
|
|
240
|
+
const query = new QueryBuilder(pattern);
|
|
241
|
+
query.filter((node)=>{
|
|
242
|
+
captured ??= node.var(name) ?? undefined;
|
|
243
|
+
return true;
|
|
244
|
+
});
|
|
245
|
+
await query.applyToFile({
|
|
246
|
+
path: filePath,
|
|
247
|
+
content: source
|
|
248
|
+
});
|
|
249
|
+
} catch {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
return captured;
|
|
253
|
+
};
|
|
229
254
|
/**
|
|
230
255
|
* Return the text of every node matching the GritQL pattern, in document order.
|
|
231
256
|
*/ export const captureAllGritQL = async (tree, filePath, pattern)=>{
|
package/src/utils/ast.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/ast.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { QueryBuilder } from '@getgrit/gritql';\nimport type { Tree } from '@nx/devkit';\nimport * as path from 'path';\nimport { updateGitIgnore } from './git';\nimport { isEsmWorkspace } from './module-format';\n\nconst GRIT_DIR = '.grit';\n\n/**\n * Normalize a relative module specifier for the workspace's module format.\n * ESM (`nodenext`) requires an explicit `.js` extension on relative imports;\n * CommonJS (`node16`) resolves them extensionless. Callers always pass the ESM\n * form (with `.js`); this strips the extension for CommonJS workspaces.\n */\nconst normalizeModuleSpecifier = (tree: Tree, from: string): string => {\n if (isEsmWorkspace(tree)) {\n return from;\n }\n const isRelative = from.startsWith('./') || from.startsWith('../');\n return isRelative && from.endsWith('.js')\n ? from.slice(0, -'.js'.length)\n : from;\n};\n\n// Pin the gritql native library's \"global\" stdlib directory to <workspace>/.grit so it doesn't try to write to /usr/local/.grit (or wherever node's grandparent resolves to).\nconst ensureGritDir = (tree: Tree) => {\n process.env.GRIT_GLOBAL_DIR ??= path.join(tree.root, GRIT_DIR);\n updateGitIgnore(tree, '.', (patterns) => [...patterns, GRIT_DIR]);\n};\n\nconst assertFilePath = (tree: Tree, filePath: string) => {\n if (!tree.exists(filePath)) {\n throw new Error(`No file located at ${filePath}`);\n }\n};\n\nexport const addDestructuredImport = async (\n tree: Tree,\n filePath: string,\n variableNames: string[],\n from: string,\n) => {\n assertFilePath(tree, filePath);\n from = normalizeModuleSpecifier(tree, from);\n\n // Check if there's an existing import from this module\n const hasExistingImport = await matchGritQL(\n tree,\n filePath,\n `\\`import { $_ } from '${from}'\\``,\n );\n\n if (hasExistingImport) {\n // For each new variable, use GritQL rewrite to add it if not already present\n for (const variableName of variableNames) {\n const localName = variableName.includes(' as ')\n ? variableName.split(' as ')[1]\n : variableName;\n // Use rewrite (=>) which correctly handles comma-separated import specifier lists\n await applyGritQL(\n tree,\n filePath,\n `\\`import { $imports } from '${from}'\\` => \\`import { $imports, ${variableName} } from '${from}'\\` where { $imports <: not contains \\`${localName}\\` }`,\n );\n }\n } else {\n // No existing import — prepend a new one (after shebang if present)\n const specifiers = variableNames.join(', ');\n const contents = tree.read(filePath)!.toString();\n const newImport = `import { ${specifiers} } from '${from}';\\n`;\n if (contents.startsWith('#!')) {\n const newlineIndex = contents.indexOf('\\n');\n tree.write(\n filePath,\n `${contents.substring(0, newlineIndex + 1)}${newImport}${contents.substring(newlineIndex + 1)}`,\n );\n } else {\n tree.write(filePath, `${newImport}${contents}`);\n }\n }\n};\n\n/**\n * Ensure a Python `from <module> import <name1>, <name2>, ...` statement\n * exists in the given file. If the module already has a `from <module> import`\n * line, any missing names are appended; otherwise a fresh import statement is\n * prepended to the file (ruff's import sorter will reorder it into place on\n * the next format pass).\n *\n * We try to append first (which only succeeds if an import-from for the\n * module already exists AND the name isn't yet in the list). If nothing\n * was rewritten after trying every requested name, we fall back to checking\n * whether the module is imported at all; if not, we prepend a fresh\n * `from <module> import ...` line.\n */\nexport const addPythonDestructuredImport = async (\n tree: Tree,\n filePath: string,\n variableNames: string[],\n from: string,\n) => {\n assertFilePath(tree, filePath);\n\n // Determine whether there's any `from <module> import ...` line in the file.\n // We detect this by attempting a no-op transformation — the file is unchanged,\n // but a successful match tells us the line exists.\n const beforeContents = tree.read(filePath)!.toString();\n let moduleAlreadyImported = false;\n for (const variableName of variableNames) {\n // Appends the name if the import-from exists and the name isn't already there.\n const appended = await applyGritQL(\n tree,\n filePath,\n `language python\\n\\`from ${from} import $names\\` where { $names <: not contains \\`${variableName}\\`, $names += \\`, ${variableName}\\` }`,\n );\n if (appended) {\n moduleAlreadyImported = true;\n }\n }\n\n // If the append succeeded for at least one name, we know the module line\n // exists; we're done. If nothing was appended we need to distinguish\n // between \"module not imported\" (need to add a new line) and \"module\n // imported but all names already present\" (no-op).\n if (moduleAlreadyImported) {\n return;\n }\n\n const allAlreadyPresent = await matchGritQL(\n tree,\n filePath,\n `language python\\n\\`from ${from} import $names\\` where { ${variableNames\n .map((n) => `$names <: contains \\`${n}\\``)\n .join(', ')} }`,\n );\n if (allAlreadyPresent) {\n return;\n }\n\n // No existing `from <module> import` line — prepend one. Ruff's import\n // sorter will place it in the right group on the next formatter pass.\n const specifiers = variableNames.join(', ');\n tree.write(filePath, `from ${from} import ${specifiers}\\n${beforeContents}`);\n};\n\n/**\n * Adds an `import <variableName> from '<from>'; statement to the beginning of the file,\n * if it doesn't already exist\n */\nexport const addSingleImport = async (\n tree: Tree,\n filePath: string,\n variableName: string,\n from: string,\n) => {\n assertFilePath(tree, filePath);\n from = normalizeModuleSpecifier(tree, from);\n\n // Check if default import already exists using GritQL\n const alreadyImported = await matchGritQL(\n tree,\n filePath,\n `\\`import ${variableName} from '${from}'\\``,\n );\n if (alreadyImported) {\n return;\n }\n\n // Prepend new import to file\n const contents = tree.read(filePath)!.toString();\n tree.write(filePath, `import ${variableName} from '${from}';\\n${contents}`);\n};\n\n/**\n * Adds an `export * from '<from>'; statement to the given TypeScript file.\n * Note that this will create the file if it does not exist in the tree.\n */\nexport const addStarExport = async (\n tree: Tree,\n filePath: string,\n from: string,\n) => {\n from = normalizeModuleSpecifier(tree, from);\n const contents = tree.read(filePath)?.toString() ?? '';\n\n // For empty/non-existent files, just write the export\n if (!contents.trim()) {\n tree.write(filePath, `export * from '${from}';\\n`);\n return;\n }\n\n // Check if already exported using GritQL\n const alreadyExported = await matchGritQL(\n tree,\n filePath,\n `\\`export * from '${from}'\\``,\n );\n if (alreadyExported) {\n return;\n }\n\n // Prepend new export to file\n tree.write(filePath, `export * from '${from}';\\n${contents}`);\n};\n\n/**\n * Return whether or not the given identifier is exported in the source file.\n * Checks for both `export { Identifier }` and `export type Identifier = ...`.\n */\nexport const hasExportDeclaration = async (\n tree: Tree,\n source: string,\n identifierName: string,\n): Promise<boolean> => {\n ensureGritDir(tree);\n const patterns = [\n `\\`export type ${identifierName} = $_\\``,\n `\\`export { ${identifierName} }\\``,\n `\\`export type { ${identifierName} } from $_\\``,\n ];\n\n for (const pattern of patterns) {\n try {\n const q = new QueryBuilder(`$p => $p where { $p <: ${pattern} }`);\n const result = await q.applyToFile({\n path: 'check.ts',\n content: source,\n });\n if (result !== null) return true;\n } catch {\n // Pattern didn't match, try next\n }\n }\n\n return false;\n};\n\n/**\n * Apply a GritQL pattern to a file in the Nx tree.\n */\nexport const applyGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<boolean> => {\n if (!tree.exists(filePath)) throw new Error(`No file at ${filePath}`);\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n const query = new QueryBuilder(pattern);\n const result = await query.applyToFile({ path: filePath, content: source });\n if (result && result.content !== source) {\n tree.write(filePath, result.content);\n return true;\n }\n return false;\n};\n\n/**\n * Check whether a GritQL pattern matches anywhere in a file.\n * Returns true if the pattern matches at least once.\n *\n * Accepts raw GritQL, including patterns that start with a `language <name>`\n * header (e.g. `language python\\n\\`print($_)\\``) — the pattern is passed\n * straight through to QueryBuilder without any wrapping rewrite.\n */\nexport const matchGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<boolean> => {\n if (!tree.exists(filePath)) return false;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n let matched = false;\n try {\n const query = new QueryBuilder(pattern);\n query.filter(() => {\n matched = true;\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return false;\n }\n return matched;\n};\n\n/**\n * Capture the source text of the first match of a GritQL pattern.\n *\n * For example `` `dependencyCheck: $_` `` returns the whole\n * `dependencyCheck: { ... }` property text. Returns undefined if nothing\n * matches. The file is not modified.\n */\nexport const captureGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<string | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n let captured: string | undefined;\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured ??= node.text();\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Return the text of every node matching the GritQL pattern, in document order.\n */\nexport const captureAllGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<string[]> => {\n if (!tree.exists(filePath)) return [];\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n const captured: string[] = [];\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured.push(node.text());\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return [];\n }\n return captured;\n};\n\n/**\n * A unique token that is a valid identifier, so it can stand in for an array\n * element or object property inside a GritQL rewrite.\n */\nexport const GRIT_INSERT_PLACEHOLDER = '__GRIT_INSERT_PLACEHOLDER__';\n\n/**\n * Apply a GritQL rewrite that inserts {@link GRIT_INSERT_PLACEHOLDER}, then\n * replace the placeholder with `text`. Routing user-provided text through a\n * placeholder keeps it out of the GritQL pattern, where quotes, backticks or\n * `${...}` would otherwise break parsing.\n *\n * Any separator (e.g. a leading `, ` when appending to an array) must be part\n * of the GritQL pattern, not `text`. The one adjustment made here: if the\n * placeholder lands after a trailing line comment (`// ...`) — which would\n * comment out the text — the text is moved to its own line.\n *\n * The caller formats afterwards. Returns true if the pattern matched and the\n * file changed.\n */\nexport const insertViaGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n text: string,\n): Promise<boolean> => {\n if (!(await applyGritQL(tree, filePath, pattern))) return false;\n const content = tree.read(filePath)!.toString();\n const at = content.indexOf(GRIT_INSERT_PLACEHOLDER);\n const lineSoFar = content.slice(content.lastIndexOf('\\n', at) + 1, at);\n const replacement = lineSoFar.includes('//') ? `\\n${text}` : text;\n\n // Function replacer so `$` in `text` isn't treated as a replacement pattern.\n tree.write(\n filePath,\n content.replace(GRIT_INSERT_PLACEHOLDER, () => replacement),\n );\n return true;\n};\n"],"names":["QueryBuilder","path","updateGitIgnore","isEsmWorkspace","GRIT_DIR","normalizeModuleSpecifier","tree","from","isRelative","startsWith","endsWith","slice","length","ensureGritDir","process","env","GRIT_GLOBAL_DIR","join","root","patterns","assertFilePath","filePath","exists","Error","addDestructuredImport","variableNames","hasExistingImport","matchGritQL","variableName","localName","includes","split","applyGritQL","specifiers","contents","read","toString","newImport","newlineIndex","indexOf","write","substring","addPythonDestructuredImport","beforeContents","moduleAlreadyImported","appended","allAlreadyPresent","map","n","addSingleImport","alreadyImported","addStarExport","trim","alreadyExported","hasExportDeclaration","source","identifierName","pattern","q","result","applyToFile","content","query","matched","filter","captureGritQL","undefined","captured","node","text","captureAllGritQL","push","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","at","lineSoFar","lastIndexOf","replacement","replace"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/ast.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { QueryBuilder } from '@getgrit/gritql';\nimport type { Tree } from '@nx/devkit';\nimport * as path from 'path';\nimport { updateGitIgnore } from './git';\nimport { isEsmWorkspace } from './module-format';\n\nconst GRIT_DIR = '.grit';\n\n/**\n * Normalize a relative module specifier for the workspace's module format.\n * ESM (`nodenext`) requires an explicit `.js` extension on relative imports;\n * CommonJS (`node16`) resolves them extensionless. Callers always pass the ESM\n * form (with `.js`); this strips the extension for CommonJS workspaces.\n */\nconst normalizeModuleSpecifier = (tree: Tree, from: string): string => {\n if (isEsmWorkspace(tree)) {\n return from;\n }\n const isRelative = from.startsWith('./') || from.startsWith('../');\n return isRelative && from.endsWith('.js')\n ? from.slice(0, -'.js'.length)\n : from;\n};\n\n// Pin the gritql native library's \"global\" stdlib directory to <workspace>/.grit so it doesn't try to write to /usr/local/.grit (or wherever node's grandparent resolves to).\nconst ensureGritDir = (tree: Tree) => {\n process.env.GRIT_GLOBAL_DIR ??= path.join(tree.root, GRIT_DIR);\n updateGitIgnore(tree, '.', (patterns) => [...patterns, GRIT_DIR]);\n};\n\nconst assertFilePath = (tree: Tree, filePath: string) => {\n if (!tree.exists(filePath)) {\n throw new Error(`No file located at ${filePath}`);\n }\n};\n\nexport const addDestructuredImport = async (\n tree: Tree,\n filePath: string,\n variableNames: string[],\n from: string,\n) => {\n assertFilePath(tree, filePath);\n from = normalizeModuleSpecifier(tree, from);\n\n // Check if there's an existing import from this module\n const hasExistingImport = await matchGritQL(\n tree,\n filePath,\n `\\`import { $_ } from '${from}'\\``,\n );\n\n if (hasExistingImport) {\n // For each new variable, use GritQL rewrite to add it if not already present\n for (const variableName of variableNames) {\n const localName = variableName.includes(' as ')\n ? variableName.split(' as ')[1]\n : variableName;\n // Use rewrite (=>) which correctly handles comma-separated import specifier lists\n await applyGritQL(\n tree,\n filePath,\n `\\`import { $imports } from '${from}'\\` => \\`import { $imports, ${variableName} } from '${from}'\\` where { $imports <: not contains \\`${localName}\\` }`,\n );\n }\n } else {\n // No existing import — prepend a new one (after shebang if present)\n const specifiers = variableNames.join(', ');\n const contents = tree.read(filePath)!.toString();\n const newImport = `import { ${specifiers} } from '${from}';\\n`;\n if (contents.startsWith('#!')) {\n const newlineIndex = contents.indexOf('\\n');\n tree.write(\n filePath,\n `${contents.substring(0, newlineIndex + 1)}${newImport}${contents.substring(newlineIndex + 1)}`,\n );\n } else {\n tree.write(filePath, `${newImport}${contents}`);\n }\n }\n};\n\n/**\n * Ensure a Python `from <module> import <name1>, <name2>, ...` statement\n * exists in the given file. If the module already has a `from <module> import`\n * line, any missing names are appended; otherwise a fresh import statement is\n * prepended to the file (ruff's import sorter will reorder it into place on\n * the next format pass).\n *\n * We try to append first (which only succeeds if an import-from for the\n * module already exists AND the name isn't yet in the list). If nothing\n * was rewritten after trying every requested name, we fall back to checking\n * whether the module is imported at all; if not, we prepend a fresh\n * `from <module> import ...` line.\n */\nexport const addPythonDestructuredImport = async (\n tree: Tree,\n filePath: string,\n variableNames: string[],\n from: string,\n) => {\n assertFilePath(tree, filePath);\n\n // Determine whether there's any `from <module> import ...` line in the file.\n // We detect this by attempting a no-op transformation — the file is unchanged,\n // but a successful match tells us the line exists.\n const beforeContents = tree.read(filePath)!.toString();\n let moduleAlreadyImported = false;\n for (const variableName of variableNames) {\n // Appends the name if the import-from exists and the name isn't already there.\n const appended = await applyGritQL(\n tree,\n filePath,\n `language python\\n\\`from ${from} import $names\\` where { $names <: not contains \\`${variableName}\\`, $names += \\`, ${variableName}\\` }`,\n );\n if (appended) {\n moduleAlreadyImported = true;\n }\n }\n\n // If the append succeeded for at least one name, we know the module line\n // exists; we're done. If nothing was appended we need to distinguish\n // between \"module not imported\" (need to add a new line) and \"module\n // imported but all names already present\" (no-op).\n if (moduleAlreadyImported) {\n return;\n }\n\n const allAlreadyPresent = await matchGritQL(\n tree,\n filePath,\n `language python\\n\\`from ${from} import $names\\` where { ${variableNames\n .map((n) => `$names <: contains \\`${n}\\``)\n .join(', ')} }`,\n );\n if (allAlreadyPresent) {\n return;\n }\n\n // No existing `from <module> import` line — prepend one. Ruff's import\n // sorter will place it in the right group on the next formatter pass.\n const specifiers = variableNames.join(', ');\n tree.write(filePath, `from ${from} import ${specifiers}\\n${beforeContents}`);\n};\n\n/**\n * Adds an `import <variableName> from '<from>'; statement to the beginning of the file,\n * if it doesn't already exist\n */\nexport const addSingleImport = async (\n tree: Tree,\n filePath: string,\n variableName: string,\n from: string,\n) => {\n assertFilePath(tree, filePath);\n from = normalizeModuleSpecifier(tree, from);\n\n // Check if default import already exists using GritQL\n const alreadyImported = await matchGritQL(\n tree,\n filePath,\n `\\`import ${variableName} from '${from}'\\``,\n );\n if (alreadyImported) {\n return;\n }\n\n // Prepend new import to file\n const contents = tree.read(filePath)!.toString();\n tree.write(filePath, `import ${variableName} from '${from}';\\n${contents}`);\n};\n\n/**\n * Adds an `export * from '<from>'; statement to the given TypeScript file.\n * Note that this will create the file if it does not exist in the tree.\n */\nexport const addStarExport = async (\n tree: Tree,\n filePath: string,\n from: string,\n) => {\n from = normalizeModuleSpecifier(tree, from);\n const contents = tree.read(filePath)?.toString() ?? '';\n\n // For empty/non-existent files, just write the export\n if (!contents.trim()) {\n tree.write(filePath, `export * from '${from}';\\n`);\n return;\n }\n\n // Check if already exported using GritQL\n const alreadyExported = await matchGritQL(\n tree,\n filePath,\n `\\`export * from '${from}'\\``,\n );\n if (alreadyExported) {\n return;\n }\n\n // Prepend new export to file\n tree.write(filePath, `export * from '${from}';\\n${contents}`);\n};\n\n/**\n * Return whether or not the given identifier is exported in the source file.\n * Checks for both `export { Identifier }` and `export type Identifier = ...`.\n */\nexport const hasExportDeclaration = async (\n tree: Tree,\n source: string,\n identifierName: string,\n): Promise<boolean> => {\n ensureGritDir(tree);\n const patterns = [\n `\\`export type ${identifierName} = $_\\``,\n `\\`export { ${identifierName} }\\``,\n `\\`export type { ${identifierName} } from $_\\``,\n ];\n\n for (const pattern of patterns) {\n try {\n const q = new QueryBuilder(`$p => $p where { $p <: ${pattern} }`);\n const result = await q.applyToFile({\n path: 'check.ts',\n content: source,\n });\n if (result !== null) return true;\n } catch {\n // Pattern didn't match, try next\n }\n }\n\n return false;\n};\n\n/**\n * Apply a GritQL pattern to a file in the Nx tree.\n */\nexport const applyGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<boolean> => {\n if (!tree.exists(filePath)) throw new Error(`No file at ${filePath}`);\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n const query = new QueryBuilder(pattern);\n const result = await query.applyToFile({ path: filePath, content: source });\n if (result && result.content !== source) {\n tree.write(filePath, result.content);\n return true;\n }\n return false;\n};\n\n/**\n * Check whether a GritQL pattern matches anywhere in a file.\n * Returns true if the pattern matches at least once.\n *\n * Accepts raw GritQL, including patterns that start with a `language <name>`\n * header (e.g. `language python\\n\\`print($_)\\``) — the pattern is passed\n * straight through to QueryBuilder without any wrapping rewrite.\n */\nexport const matchGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<boolean> => {\n if (!tree.exists(filePath)) return false;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n let matched = false;\n try {\n const query = new QueryBuilder(pattern);\n query.filter(() => {\n matched = true;\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return false;\n }\n return matched;\n};\n\n/**\n * Capture the source text of the first match of a GritQL pattern.\n *\n * For example `` `dependencyCheck: $_` `` returns the whole\n * `dependencyCheck: { ... }` property text. Returns undefined if nothing\n * matches. The file is not modified.\n */\nexport const captureGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<string | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n let captured: string | undefined;\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured ??= node.text();\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Like `captureGritQL`, but returns one metavariable's binding (e.g. `mod`\n * for `$mod`) instead of the whole matched node.\n */\nexport const captureGritQLVariable = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n variableName: string,\n): Promise<string | undefined> => {\n if (!tree.exists(filePath)) return undefined;\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n // The underlying binding lookup requires the `$` sigil.\n const name = variableName.startsWith('$') ? variableName : `$${variableName}`;\n let captured: string | undefined;\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured ??= node.var(name) ?? undefined;\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return undefined;\n }\n return captured;\n};\n\n/**\n * Return the text of every node matching the GritQL pattern, in document order.\n */\nexport const captureAllGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n): Promise<string[]> => {\n if (!tree.exists(filePath)) return [];\n ensureGritDir(tree);\n const source = tree.read(filePath)!.toString();\n const captured: string[] = [];\n try {\n const query = new QueryBuilder(pattern);\n query.filter((node) => {\n captured.push(node.text());\n return true;\n });\n await query.applyToFile({ path: filePath, content: source });\n } catch {\n return [];\n }\n return captured;\n};\n\n/**\n * A unique token that is a valid identifier, so it can stand in for an array\n * element or object property inside a GritQL rewrite.\n */\nexport const GRIT_INSERT_PLACEHOLDER = '__GRIT_INSERT_PLACEHOLDER__';\n\n/**\n * Apply a GritQL rewrite that inserts {@link GRIT_INSERT_PLACEHOLDER}, then\n * replace the placeholder with `text`. Routing user-provided text through a\n * placeholder keeps it out of the GritQL pattern, where quotes, backticks or\n * `${...}` would otherwise break parsing.\n *\n * Any separator (e.g. a leading `, ` when appending to an array) must be part\n * of the GritQL pattern, not `text`. The one adjustment made here: if the\n * placeholder lands after a trailing line comment (`// ...`) — which would\n * comment out the text — the text is moved to its own line.\n *\n * The caller formats afterwards. Returns true if the pattern matched and the\n * file changed.\n */\nexport const insertViaGritQL = async (\n tree: Tree,\n filePath: string,\n pattern: string,\n text: string,\n): Promise<boolean> => {\n if (!(await applyGritQL(tree, filePath, pattern))) return false;\n const content = tree.read(filePath)!.toString();\n const at = content.indexOf(GRIT_INSERT_PLACEHOLDER);\n const lineSoFar = content.slice(content.lastIndexOf('\\n', at) + 1, at);\n const replacement = lineSoFar.includes('//') ? `\\n${text}` : text;\n\n // Function replacer so `$` in `text` isn't treated as a replacement pattern.\n tree.write(\n filePath,\n content.replace(GRIT_INSERT_PLACEHOLDER, () => replacement),\n );\n return true;\n};\n"],"names":["QueryBuilder","path","updateGitIgnore","isEsmWorkspace","GRIT_DIR","normalizeModuleSpecifier","tree","from","isRelative","startsWith","endsWith","slice","length","ensureGritDir","process","env","GRIT_GLOBAL_DIR","join","root","patterns","assertFilePath","filePath","exists","Error","addDestructuredImport","variableNames","hasExistingImport","matchGritQL","variableName","localName","includes","split","applyGritQL","specifiers","contents","read","toString","newImport","newlineIndex","indexOf","write","substring","addPythonDestructuredImport","beforeContents","moduleAlreadyImported","appended","allAlreadyPresent","map","n","addSingleImport","alreadyImported","addStarExport","trim","alreadyExported","hasExportDeclaration","source","identifierName","pattern","q","result","applyToFile","content","query","matched","filter","captureGritQL","undefined","captured","node","text","captureGritQLVariable","name","var","captureAllGritQL","push","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","at","lineSoFar","lastIndexOf","replacement","replace"],"mappings":"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"}
|
package/src/utils/connection/open-api/files/components/__apiNameClassName__Provider.tsx.template
CHANGED
|
@@ -26,6 +26,8 @@ const useCreate<%- apiNameClassName %>Client = (): <%- apiNameClassName %> => {
|
|
|
26
26
|
const runtimeConfig = useRuntimeConfig();
|
|
27
27
|
<%_ if (isAgentRuntime) { _%>
|
|
28
28
|
const agentRuntimeValue = runtimeConfig.agentRuntimes.<%- apiNameClassName %>;
|
|
29
|
+
// A local-dev override is a plain URL; otherwise it's the agent's runtime
|
|
30
|
+
// ARN, so build the invocation URL from it.
|
|
29
31
|
const apiUrl = agentRuntimeValue.startsWith('arn:')
|
|
30
32
|
? buildAgentCoreHttpUrl(agentRuntimeValue)
|
|
31
33
|
: agentRuntimeValue;
|
|
@@ -18,7 +18,8 @@ import { compare } from 'semver';
|
|
|
18
18
|
* - The weekly `update-versions` PR backfills the version of the release that
|
|
19
19
|
* shipped each migration, moving and re-keying it accordingly
|
|
20
20
|
* (`scripts/backfill-migration-versions.ts`), so source converges on the
|
|
21
|
-
* versions of everything already released.
|
|
21
|
+
* versions of everything already released. `packageJsonUpdates` entries are
|
|
22
|
+
* dated in place there too, since their keys never change.
|
|
22
23
|
*
|
|
23
24
|
* A version already in source always wins, so backfilled entries are stable.
|
|
24
25
|
*
|
|
@@ -32,8 +33,9 @@ export interface MigrationsJson {
|
|
|
32
33
|
} & Record<string, unknown>>;
|
|
33
34
|
/**
|
|
34
35
|
* Declarative dependency bumps `nx migrate` applies to the root manifest.
|
|
35
|
-
* Keyed
|
|
36
|
-
*
|
|
36
|
+
* Keyed by what the bump targets rather than the release that ships it, so an
|
|
37
|
+
* entry is unique from the moment it is written and one release's bump can sit
|
|
38
|
+
* beside the next; nx itself gates on the entry's `version`.
|
|
37
39
|
*/
|
|
38
40
|
packageJsonUpdates?: Record<string, {
|
|
39
41
|
version: string;
|
|
@@ -44,15 +46,19 @@ export declare const compareVersions: typeof compare;
|
|
|
44
46
|
/** Whether a string is an exact semver version. */
|
|
45
47
|
export declare const isValidVersion: (version: string) => boolean;
|
|
46
48
|
/**
|
|
47
|
-
* Map of
|
|
48
|
-
*
|
|
49
|
-
* in source wins, so its history doesn't
|
|
50
|
-
* been released is absent.
|
|
49
|
+
* Map of entry key -> version of the earliest release that registers it, across
|
|
50
|
+
* both `generators` and `packageJsonUpdates`. Resolved only for the entries still
|
|
51
|
+
* missing a version (one already recorded in source wins, so its history doesn't
|
|
52
|
+
* need reading). An entry that hasn't been released is absent.
|
|
51
53
|
*
|
|
52
54
|
* Walks releases newest first and stops as soon as every entry is resolved: an
|
|
53
55
|
* entry that has disappeared from a release's `migrations.json` was first
|
|
54
56
|
* registered by the release after it, which is the one that shipped it.
|
|
55
57
|
*
|
|
58
|
+
* Both sections resolve the same way and share the walk, so the release doesn't
|
|
59
|
+
* read tag history twice. Keys can't collide: a migration is keyed by its own
|
|
60
|
+
* name, an nx bump by the nx version it moves to.
|
|
61
|
+
*
|
|
56
62
|
* @param migrations parsed source migrations.json
|
|
57
63
|
* @param versions released versions in descending semver order
|
|
58
64
|
* @param readReleasedMigrations reads the `migrations.json` published by a given
|
|
@@ -61,9 +67,8 @@ export declare const isValidVersion: (version: string) => boolean;
|
|
|
61
67
|
export declare const readShippedMigrationVersions: (migrations: MigrationsJson, versions: string[], readReleasedMigrations: (version: string) => MigrationsJson | undefined) => Record<string, string>;
|
|
62
68
|
/**
|
|
63
69
|
* Return a copy of the migrations collection with a `version` stamped onto
|
|
64
|
-
* every generator entry, preserving any already present, and
|
|
65
|
-
* `packageJsonUpdates` entry still
|
|
66
|
-
* ships under.
|
|
70
|
+
* every generator entry, preserving any already present, and the pending version
|
|
71
|
+
* recorded on any `packageJsonUpdates` entry still holding `latest`.
|
|
67
72
|
*
|
|
68
73
|
* @param migrations parsed migrations.json to stamp
|
|
69
74
|
* @param shippedVersions migration key -> version of the earliest release
|