@intentius/chant-lexicon-aws 0.0.18 → 0.0.22

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.
@@ -2838,6 +2838,9 @@
2838
2838
  }
2839
2839
  ],
2840
2840
  "propertyConstraints": {
2841
+ "ActionsEnabled": {
2842
+ "default": true
2843
+ },
2841
2844
  "TreatMissingData": {
2842
2845
  "enum": [
2843
2846
  "breaching",
@@ -2845,9 +2848,6 @@
2845
2848
  "missing",
2846
2849
  "notBreaching"
2847
2850
  ]
2848
- },
2849
- "ActionsEnabled": {
2850
- "default": true
2851
2851
  }
2852
2852
  },
2853
2853
  "createOnly": [
@@ -23182,6 +23182,11 @@
23182
23182
  "tagUpdatable": true
23183
23183
  }
23184
23184
  },
23185
+ "ConnectQueue_EmailAddress": {
23186
+ "resourceType": "AWS::Connect::Queue.EmailAddress",
23187
+ "kind": "property",
23188
+ "lexicon": "aws"
23189
+ },
23185
23190
  "ConnectQueue_OutboundCallerConfig": {
23186
23191
  "resourceType": "AWS::Connect::Queue.OutboundCallerConfig",
23187
23192
  "kind": "property",
@@ -23357,6 +23362,11 @@
23357
23362
  "kind": "property",
23358
23363
  "lexicon": "aws"
23359
23364
  },
23365
+ "ConnectSecurityProfile_FlowModule": {
23366
+ "resourceType": "AWS::Connect::SecurityProfile.FlowModule",
23367
+ "kind": "property",
23368
+ "lexicon": "aws"
23369
+ },
23360
23370
  "ConnectSecurityProfile_PrimaryAttributeAccessControlConfigurationItem": {
23361
23371
  "resourceType": "AWS::Connect::SecurityProfile.PrimaryAttributeAccessControlConfigurationItem",
23362
23372
  "kind": "property",
@@ -24776,49 +24786,49 @@
24776
24786
  "DeploymentDetails": "DeploymentDetails",
24777
24787
  "GameServerContainerGroupDefinitionArn": "GameServerContainerGroupDefinitionArn",
24778
24788
  "PerInstanceContainerGroupDefinitionArn": "PerInstanceContainerGroupDefinitionArn",
24779
- "MaximumGameServerContainerGroupsPerInstance": "MaximumGameServerContainerGroupsPerInstance"
24789
+ "MaximumGameServerContainerGroupsPerInstance": "MaximumGameServerContainerGroupsPerInstance",
24790
+ "Locations_*_PlayerGatewayStatus": "Locations.*.PlayerGatewayStatus"
24780
24791
  },
24781
24792
  "propertyConstraints": {
24782
- "GameServerContainerGroupDefinitionName": {
24783
- "pattern": "^[a-zA-Z0-9\\-]+$|^arn:.*:containergroupdefinition\\/[a-zA-Z0-9\\-]+(:[0-9]+)?$",
24793
+ "FleetId": {
24794
+ "pattern": "^[a-z]*fleet-[a-zA-Z0-9\\-]+",
24784
24795
  "minLength": 1,
24785
- "maxLength": 512
24796
+ "maxLength": 128
24797
+ },
24798
+ "FleetRoleArn": {
24799
+ "pattern": "^arn:aws(-.*)?:[a-z-]+:(([a-z]+-)+[0-9])?:([0-9]{12})?:[^.]+$",
24800
+ "minLength": 1,
24801
+ "maxLength": 256
24786
24802
  },
24787
24803
  "Description": {
24788
24804
  "minLength": 1,
24789
24805
  "maxLength": 1024
24790
24806
  },
24791
- "MaximumGameServerContainerGroupsPerInstance": {
24792
- "minimum": 1,
24793
- "maximum": 5000
24794
- },
24795
- "GameServerContainerGroupsPerInstance": {
24796
- "minimum": 1,
24797
- "maximum": 5000
24807
+ "GameServerContainerGroupDefinitionName": {
24808
+ "pattern": "^[a-zA-Z0-9\\-]+$|^arn:.*:containergroupdefinition\\/[a-zA-Z0-9\\-]+(:[0-9]+)?$",
24809
+ "minLength": 1,
24810
+ "maxLength": 512
24798
24811
  },
24799
- "PerInstanceContainerGroupDefinitionArn": {
24812
+ "GameServerContainerGroupDefinitionArn": {
24800
24813
  "pattern": "^arn:.*:containergroupdefinition\\/[a-zA-Z0-9\\-]+(:[0-9]+)?$|^$",
24801
24814
  "maxLength": 512
24802
24815
  },
24803
- "FleetId": {
24804
- "pattern": "^[a-z]*fleet-[a-zA-Z0-9\\-]+",
24805
- "minLength": 1,
24806
- "maxLength": 128
24807
- },
24808
- "InstanceType": {
24816
+ "PerInstanceContainerGroupDefinitionName": {
24817
+ "pattern": "^[a-zA-Z0-9\\-]+$|^arn:.*:containergroupdefinition\\/[a-zA-Z0-9\\-]+(:[0-9]+)?$",
24809
24818
  "minLength": 1,
24810
- "maxLength": 1024
24819
+ "maxLength": 512
24811
24820
  },
24812
- "FleetArn": {
24813
- "pattern": "^arn:.*:[a-z]*fleet\\/[a-z]*fleet-[a-zA-Z0-9\\-]+$",
24814
- "minLength": 1,
24821
+ "PerInstanceContainerGroupDefinitionArn": {
24822
+ "pattern": "^arn:.*:containergroupdefinition\\/[a-zA-Z0-9\\-]+(:[0-9]+)?$|^$",
24815
24823
  "maxLength": 512
24816
24824
  },
24817
- "BillingType": {
24818
- "enum": [
24819
- "ON_DEMAND",
24820
- "SPOT"
24821
- ]
24825
+ "GameServerContainerGroupsPerInstance": {
24826
+ "minimum": 1,
24827
+ "maximum": 5000
24828
+ },
24829
+ "MaximumGameServerContainerGroupsPerInstance": {
24830
+ "minimum": 1,
24831
+ "maximum": 5000
24822
24832
  },
24823
24833
  "Status": {
24824
24834
  "enum": [
@@ -24831,15 +24841,15 @@
24831
24841
  "DELETING"
24832
24842
  ]
24833
24843
  },
24834
- "FleetRoleArn": {
24835
- "pattern": "^arn:aws(-.*)?:[a-z-]+:(([a-z]+-)+[0-9])?:([0-9]{12})?:[^.]+$",
24844
+ "InstanceType": {
24836
24845
  "minLength": 1,
24837
- "maxLength": 256
24846
+ "maxLength": 1024
24838
24847
  },
24839
- "PerInstanceContainerGroupDefinitionName": {
24840
- "pattern": "^[a-zA-Z0-9\\-]+$|^arn:.*:containergroupdefinition\\/[a-zA-Z0-9\\-]+(:[0-9]+)?$",
24841
- "minLength": 1,
24842
- "maxLength": 512
24848
+ "BillingType": {
24849
+ "enum": [
24850
+ "ON_DEMAND",
24851
+ "SPOT"
24852
+ ]
24843
24853
  },
24844
24854
  "NewGameSessionProtectionPolicy": {
24845
24855
  "enum": [
@@ -24847,14 +24857,23 @@
24847
24857
  "NoProtection"
24848
24858
  ]
24849
24859
  },
24850
- "GameServerContainerGroupDefinitionArn": {
24851
- "pattern": "^arn:.*:containergroupdefinition\\/[a-zA-Z0-9\\-]+(:[0-9]+)?$|^$",
24860
+ "PlayerGatewayMode": {
24861
+ "enum": [
24862
+ "DISABLED",
24863
+ "ENABLED",
24864
+ "REQUIRED"
24865
+ ]
24866
+ },
24867
+ "FleetArn": {
24868
+ "pattern": "^arn:.*:[a-z]*fleet\\/[a-z]*fleet-[a-zA-Z0-9\\-]+$",
24869
+ "minLength": 1,
24852
24870
  "maxLength": 512
24853
24871
  }
24854
24872
  },
24855
24873
  "createOnly": [
24856
24874
  "InstanceType",
24857
- "BillingType"
24875
+ "BillingType",
24876
+ "PlayerGatewayMode"
24858
24877
  ],
24859
24878
  "writeOnly": [
24860
24879
  "DeploymentConfiguration",
@@ -25171,6 +25190,11 @@
25171
25190
  "kind": "property",
25172
25191
  "lexicon": "aws"
25173
25192
  },
25193
+ "ContentConfiguration": {
25194
+ "resourceType": "AWS::BedrockAgentCore::Memory.ContentConfiguration",
25195
+ "kind": "property",
25196
+ "lexicon": "aws"
25197
+ },
25174
25198
  "ContentFilterConfig": {
25175
25199
  "resourceType": "AWS::Bedrock::Guardrail.ContentFilterConfig",
25176
25200
  "kind": "property",
@@ -46257,6 +46281,11 @@
46257
46281
  "kind": "property",
46258
46282
  "lexicon": "aws"
46259
46283
  },
46284
+ "FlowModule": {
46285
+ "resourceType": "AWS::Connect::SecurityProfile.FlowModule",
46286
+ "kind": "property",
46287
+ "lexicon": "aws"
46288
+ },
46260
46289
  "FlowOutput": {
46261
46290
  "resourceType": "AWS::MediaConnect::FlowOutput",
46262
46291
  "kind": "resource",
@@ -47940,18 +47969,10 @@
47940
47969
  "lexicon": "aws",
47941
47970
  "attrs": {
47942
47971
  "FleetId": "FleetId",
47943
- "FleetArn": "FleetArn"
47972
+ "FleetArn": "FleetArn",
47973
+ "Locations_*_PlayerGatewayStatus": "Locations.*.PlayerGatewayStatus"
47944
47974
  },
47945
47975
  "propertyConstraints": {
47946
- "Description": {
47947
- "minLength": 1,
47948
- "maxLength": 1024
47949
- },
47950
- "PeerVpcId": {
47951
- "pattern": "^vpc-\\S+",
47952
- "minLength": 1,
47953
- "maxLength": 1024
47954
- },
47955
47976
  "ApplyCapacity": {
47956
47977
  "enum": [
47957
47978
  "ON_UPDATE",
@@ -47965,67 +47986,83 @@
47965
47986
  "ANYWHERE"
47966
47987
  ]
47967
47988
  },
47968
- "Name": {
47989
+ "Description": {
47969
47990
  "minLength": 1,
47970
47991
  "maxLength": 1024
47971
47992
  },
47993
+ "DesiredEC2Instances": {
47994
+ "minimum": 0
47995
+ },
47996
+ "EC2InstanceType": {
47997
+ "pattern": "^.*..*$"
47998
+ },
47999
+ "FleetType": {
48000
+ "enum": [
48001
+ "ON_DEMAND",
48002
+ "SPOT"
48003
+ ]
48004
+ },
47972
48005
  "InstanceRoleARN": {
47973
48006
  "pattern": "^arn:aws(-.*)?:[a-z-]+:(([a-z]+-)+[0-9])?:([0-9]{12})?:[^.]+$",
47974
48007
  "minLength": 1
47975
48008
  },
47976
- "FleetId": {
47977
- "pattern": "^fleet-\\S+"
47978
- },
47979
48009
  "InstanceRoleCredentialsProvider": {
47980
48010
  "enum": [
47981
48011
  "SHARED_CREDENTIAL_FILE"
47982
48012
  ]
47983
48013
  },
47984
- "DesiredEC2Instances": {
48014
+ "MaxSize": {
47985
48015
  "minimum": 0
47986
48016
  },
47987
- "FleetArn": {
47988
- "pattern": "^arn:.*:fleet/[a-z]*fleet-[a-zA-Z0-9\\-]+$"
48017
+ "MinSize": {
48018
+ "minimum": 0
47989
48019
  },
47990
- "ServerLaunchParameters": {
48020
+ "Name": {
47991
48021
  "minLength": 1,
47992
48022
  "maxLength": 1024
47993
48023
  },
47994
- "FleetType": {
47995
- "enum": [
47996
- "ON_DEMAND",
47997
- "SPOT"
47998
- ]
47999
- },
48000
48024
  "NewGameSessionProtectionPolicy": {
48001
48025
  "enum": [
48002
48026
  "FullProtection",
48003
48027
  "NoProtection"
48004
48028
  ]
48005
48029
  },
48030
+ "PeerVpcAwsAccountId": {
48031
+ "pattern": "^[0-9]{12}$",
48032
+ "minLength": 1,
48033
+ "maxLength": 1024
48034
+ },
48035
+ "PeerVpcId": {
48036
+ "pattern": "^vpc-\\S+",
48037
+ "minLength": 1,
48038
+ "maxLength": 1024
48039
+ },
48040
+ "FleetId": {
48041
+ "pattern": "^fleet-\\S+"
48042
+ },
48043
+ "BuildId": {
48044
+ "pattern": "^build-\\S+|^arn:.*:build/build-\\S+"
48045
+ },
48006
48046
  "ScriptId": {
48007
48047
  "pattern": "^script-\\S+|^arn:.*:script/script-\\S+"
48008
48048
  },
48009
- "MaxSize": {
48010
- "minimum": 0
48011
- },
48012
- "ServerLaunchPath": {
48049
+ "ServerLaunchParameters": {
48013
48050
  "minLength": 1,
48014
48051
  "maxLength": 1024
48015
48052
  },
48016
- "MinSize": {
48017
- "minimum": 0
48018
- },
48019
- "PeerVpcAwsAccountId": {
48020
- "pattern": "^[0-9]{12}$",
48053
+ "ServerLaunchPath": {
48021
48054
  "minLength": 1,
48022
48055
  "maxLength": 1024
48023
48056
  },
48024
- "BuildId": {
48025
- "pattern": "^build-\\S+|^arn:.*:build/build-\\S+"
48057
+ "FleetArn": {
48058
+ "pattern": "^arn:.*:fleet/[a-z]*fleet-[a-zA-Z0-9\\-]+$"
48026
48059
  },
48027
- "EC2InstanceType": {
48028
- "pattern": "^.*..*$"
48060
+ "PlayerGatewayMode": {
48061
+ "enum": [
48062
+ "DISABLED",
48063
+ "ENABLED",
48064
+ "REQUIRED"
48065
+ ]
48029
48066
  }
48030
48067
  },
48031
48068
  "createOnly": [
@@ -48041,7 +48078,9 @@
48041
48078
  "ScriptId",
48042
48079
  "ServerLaunchParameters",
48043
48080
  "ServerLaunchPath",
48044
- "ComputeType"
48081
+ "ComputeType",
48082
+ "PlayerGatewayMode",
48083
+ "PlayerGatewayConfiguration"
48045
48084
  ],
48046
48085
  "writeOnly": [
48047
48086
  "ApplyCapacity"
@@ -48093,6 +48132,11 @@
48093
48132
  "kind": "property",
48094
48133
  "lexicon": "aws"
48095
48134
  },
48135
+ "GameLiftFleet_PlayerGatewayConfiguration": {
48136
+ "resourceType": "AWS::GameLift::Fleet.PlayerGatewayConfiguration",
48137
+ "kind": "property",
48138
+ "lexicon": "aws"
48139
+ },
48096
48140
  "GameLiftFleet_ResourceCreationLimitPolicy": {
48097
48141
  "resourceType": "AWS::GameLift::Fleet.ResourceCreationLimitPolicy",
48098
48142
  "kind": "property",
@@ -59649,6 +59693,11 @@
59649
59693
  "kind": "property",
59650
59694
  "lexicon": "aws"
59651
59695
  },
59696
+ "KinesisResource": {
59697
+ "resourceType": "AWS::BedrockAgentCore::Memory.KinesisResource",
59698
+ "kind": "property",
59699
+ "lexicon": "aws"
59700
+ },
59652
59701
  "KinesisResourcePolicy": {
59653
59702
  "resourceType": "AWS::Kinesis::ResourcePolicy",
59654
59703
  "kind": "resource",
@@ -68804,6 +68853,11 @@
68804
68853
  "kind": "property",
68805
68854
  "lexicon": "aws"
68806
68855
  },
68856
+ "Memory_ContentConfiguration": {
68857
+ "resourceType": "AWS::BedrockAgentCore::Memory.ContentConfiguration",
68858
+ "kind": "property",
68859
+ "lexicon": "aws"
68860
+ },
68807
68861
  "Memory_CustomConfigurationInput": {
68808
68862
  "resourceType": "AWS::BedrockAgentCore::Memory.CustomConfigurationInput",
68809
68863
  "kind": "property",
@@ -68849,6 +68903,11 @@
68849
68903
  "kind": "property",
68850
68904
  "lexicon": "aws"
68851
68905
  },
68906
+ "Memory_KinesisResource": {
68907
+ "resourceType": "AWS::BedrockAgentCore::Memory.KinesisResource",
68908
+ "kind": "property",
68909
+ "lexicon": "aws"
68910
+ },
68852
68911
  "Memory_MemoryStrategy": {
68853
68912
  "resourceType": "AWS::BedrockAgentCore::Memory.MemoryStrategy",
68854
68913
  "kind": "property",
@@ -68899,6 +68958,16 @@
68899
68958
  "kind": "property",
68900
68959
  "lexicon": "aws"
68901
68960
  },
68961
+ "Memory_StreamDeliveryResource": {
68962
+ "resourceType": "AWS::BedrockAgentCore::Memory.StreamDeliveryResource",
68963
+ "kind": "property",
68964
+ "lexicon": "aws"
68965
+ },
68966
+ "Memory_StreamDeliveryResources": {
68967
+ "resourceType": "AWS::BedrockAgentCore::Memory.StreamDeliveryResources",
68968
+ "kind": "property",
68969
+ "lexicon": "aws"
68970
+ },
68902
68971
  "Memory_SummaryConsolidationOverride": {
68903
68972
  "resourceType": "AWS::BedrockAgentCore::Memory.SummaryConsolidationOverride",
68904
68973
  "kind": "property",
@@ -79664,6 +79733,11 @@
79664
79733
  "kind": "property",
79665
79734
  "lexicon": "aws"
79666
79735
  },
79736
+ "PlayerGatewayConfiguration": {
79737
+ "resourceType": "AWS::GameLift::Fleet.PlayerGatewayConfiguration",
79738
+ "kind": "property",
79739
+ "lexicon": "aws"
79740
+ },
79667
79741
  "PlayerLatencyPolicy": {
79668
79742
  "resourceType": "AWS::GameLift::GameSessionQueue.PlayerLatencyPolicy",
79669
79743
  "kind": "property",
@@ -99734,6 +99808,11 @@
99734
99808
  "kind": "property",
99735
99809
  "lexicon": "aws"
99736
99810
  },
99811
+ "SamplingRateBoost": {
99812
+ "resourceType": "AWS::XRay::SamplingRule.SamplingRateBoost",
99813
+ "kind": "property",
99814
+ "lexicon": "aws"
99815
+ },
99737
99816
  "SamplingRule": {
99738
99817
  "resourceType": "AWS::XRay::SamplingRule",
99739
99818
  "kind": "resource",
@@ -99768,6 +99847,11 @@
99768
99847
  "kind": "property",
99769
99848
  "lexicon": "aws"
99770
99849
  },
99850
+ "SamplingRule_SamplingRateBoost": {
99851
+ "resourceType": "AWS::XRay::SamplingRule.SamplingRateBoost",
99852
+ "kind": "property",
99853
+ "lexicon": "aws"
99854
+ },
99771
99855
  "SamplingRule_SamplingRule": {
99772
99856
  "resourceType": "AWS::XRay::SamplingRule.SamplingRule",
99773
99857
  "kind": "property",
@@ -106486,6 +106570,16 @@
106486
106570
  "kind": "property",
106487
106571
  "lexicon": "aws"
106488
106572
  },
106573
+ "StreamDeliveryResource": {
106574
+ "resourceType": "AWS::BedrockAgentCore::Memory.StreamDeliveryResource",
106575
+ "kind": "property",
106576
+ "lexicon": "aws"
106577
+ },
106578
+ "StreamDeliveryResources": {
106579
+ "resourceType": "AWS::BedrockAgentCore::Memory.StreamDeliveryResources",
106580
+ "kind": "property",
106581
+ "lexicon": "aws"
106582
+ },
106489
106583
  "StreamEncryption": {
106490
106584
  "resourceType": "AWS::Kinesis::Stream.StreamEncryption",
106491
106585
  "kind": "property",
@@ -73,6 +73,10 @@ function matchesCondition(condition: unknown, properties: Record<string, unknown
73
73
  if ("enum" in s && Array.isArray(s.enum)) {
74
74
  if (!s.enum.includes(properties[propName])) return false;
75
75
  }
76
+ if ("pattern" in s && typeof s.pattern === "string") {
77
+ const val = properties[propName];
78
+ if (typeof val !== "string" || !new RegExp(s.pattern).test(val)) return false;
79
+ }
76
80
  }
77
81
  }
78
82
 
package/src/plugin.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { createRequire } from "module";
2
- import type { LexiconPlugin, IntrinsicDef, SkillDefinition } from "@intentius/chant/lexicon";
2
+ import type { LexiconPlugin, IntrinsicDef, SkillDefinition, ResourceMetadata } from "@intentius/chant/lexicon";
3
3
  const require = createRequire(import.meta.url);
4
4
  import type { LintRule } from "@intentius/chant/lint/rule";
5
5
  import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
@@ -392,7 +392,7 @@ user-invocable: true
392
392
 
393
393
  ## How chant and CloudFormation relate
394
394
 
395
- chant is a **synthesis-only** tool — it compiles TypeScript source files into CloudFormation JSON (or YAML). chant does NOT call AWS APIs. Your job as an agent is to bridge the two:
395
+ chant is a **synthesis compiler** — it compiles TypeScript source files into CloudFormation JSON (or YAML). \`chant build\` does not call AWS APIs; synthesis is pure and deterministic. The optional \`chant state snapshot\` command queries AWS APIs to capture deployment metadata (physical IDs, status, outputs) for observability. Your job as an agent is to bridge synthesis and deployment:
396
396
 
397
397
  - Use **chant** for: build, lint, diff (local template comparison)
398
398
  - Use **AWS CLI** for: validate-template, deploy, change sets, rollback, drift detection, and all stack operations
@@ -955,6 +955,91 @@ aws cloudformation wait stack-update-complete --stack-name my-app-prod`,
955
955
  return awsHover(ctx);
956
956
  },
957
957
 
958
+ async describeResources(options: {
959
+ environment: string;
960
+ buildOutput: string;
961
+ entityNames: string[];
962
+ }): Promise<Record<string, ResourceMetadata>> {
963
+ const { getRuntime } = await import("@intentius/chant/runtime-adapter");
964
+ const rt = getRuntime();
965
+ const resources: Record<string, ResourceMetadata> = {};
966
+
967
+ // Derive stack name: environment-based convention
968
+ // Try to parse the build output to detect stack name from Metadata or use convention
969
+ const stackName = `${options.environment}`;
970
+
971
+ // Describe stack resources
972
+ const listResult = await rt.spawn([
973
+ "aws", "cloudformation", "describe-stack-resources",
974
+ "--stack-name", stackName,
975
+ "--output", "json",
976
+ ]);
977
+
978
+ if (listResult.exitCode !== 0) {
979
+ throw new Error(`Failed to describe stack "${stackName}": ${listResult.stderr}`);
980
+ }
981
+
982
+ const data = JSON.parse(listResult.stdout) as {
983
+ StackResources: Array<{
984
+ LogicalResourceId: string;
985
+ ResourceType: string;
986
+ PhysicalResourceId: string;
987
+ ResourceStatus: string;
988
+ Timestamp: string;
989
+ }>;
990
+ };
991
+
992
+ // Map logical names from build to stack resources
993
+ const stackResourceMap = new Map<string, typeof data.StackResources[0]>();
994
+ for (const r of data.StackResources) {
995
+ stackResourceMap.set(r.LogicalResourceId, r);
996
+ }
997
+
998
+ // Get stack outputs
999
+ const describeResult = await rt.spawn([
1000
+ "aws", "cloudformation", "describe-stacks",
1001
+ "--stack-name", stackName,
1002
+ "--output", "json",
1003
+ ]);
1004
+
1005
+ let stackOutputs: Record<string, string> = {};
1006
+ if (describeResult.exitCode === 0) {
1007
+ const stacks = JSON.parse(describeResult.stdout) as {
1008
+ Stacks: Array<{ Outputs?: Array<{ OutputKey: string; OutputValue: string }> }>;
1009
+ };
1010
+ if (stacks.Stacks[0]?.Outputs) {
1011
+ for (const o of stacks.Stacks[0].Outputs) {
1012
+ stackOutputs[o.OutputKey] = o.OutputValue;
1013
+ }
1014
+ }
1015
+ }
1016
+
1017
+ for (const entityName of options.entityNames) {
1018
+ const stackResource = stackResourceMap.get(entityName);
1019
+ if (!stackResource) continue;
1020
+
1021
+ const attributes: Record<string, unknown> = {};
1022
+ // Include stack outputs as attributes (scrub sensitive ones)
1023
+ for (const [key, value] of Object.entries(stackOutputs)) {
1024
+ if (/password|secret|token|key/i.test(key)) {
1025
+ attributes[key] = "[REDACTED]";
1026
+ } else {
1027
+ attributes[key] = value;
1028
+ }
1029
+ }
1030
+
1031
+ resources[entityName] = {
1032
+ type: stackResource.ResourceType,
1033
+ physicalId: stackResource.PhysicalResourceId,
1034
+ status: stackResource.ResourceStatus,
1035
+ lastUpdated: stackResource.Timestamp,
1036
+ attributes: Object.keys(attributes).length > 0 ? attributes : undefined,
1037
+ };
1038
+ }
1039
+
1040
+ return resources;
1041
+ },
1042
+
958
1043
  mcpTools(): McpToolContribution[] {
959
1044
  return [
960
1045
  {
@@ -33,6 +33,9 @@ AWS Lexicon (CloudFormation) K8s Lexicon (kubectl apply)
33
33
  # Build CloudFormation template
34
34
  chant build src/infra/ --output infra.json
35
35
 
36
+ # See what changed since last deploy (compares current build against last snapshot's digest)
37
+ chant state diff staging aws
38
+
36
39
  # Deploy
37
40
  aws cloudformation deploy \
38
41
  --template-file infra.json \