@prism-d1/cli 1.0.62 → 1.0.65

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.
@@ -0,0 +1,302 @@
1
+ /**
2
+ * PRISM D1 — OTEL Collector construct (opt-in).
3
+ *
4
+ * Server side of `codeburn sync`: an HTTP API serving the codeburn discovery
5
+ * doc and an OTLP/HTTP traces endpoint, authorized by OIDC JWT.
6
+ *
7
+ * Enable with: cdk deploy -c enableOtelCollector=true
8
+ * BYO IdP with: -c otelIssuer=... -c otelClientId=... [-c otelIdentityClaim=email]
9
+ *
10
+ * Default mode provisions a Cognito User Pool (admin-create-user only,
11
+ * username = email, PKCE public client) with loopback callback URLs matching
12
+ * codeburn's fixed callback ports (19876-19878). BYO mode skips Cognito and
13
+ * wires the JWT authorizer to the external issuer.
14
+ *
15
+ * Data flow: codeburn sync push → API Gateway (JWT authorizer) → receiver
16
+ * Lambda → S3 raw OTLP archive (external contract) + DynamoDB span/aggregate
17
+ * rows (PRISM dashboards).
18
+ */
19
+
20
+ import * as cdk from 'aws-cdk-lib';
21
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
22
+ import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
23
+ import * as cognito from 'aws-cdk-lib/aws-cognito';
24
+ import * as s3 from 'aws-cdk-lib/aws-s3';
25
+ import * as kms from 'aws-cdk-lib/aws-kms';
26
+ import * as logs from 'aws-cdk-lib/aws-logs';
27
+ import * as apigwv2 from 'aws-cdk-lib/aws-apigatewayv2';
28
+ import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations';
29
+ import { HttpJwtAuthorizer } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
30
+ import * as path from 'path';
31
+ import { Construct } from 'constructs';
32
+ import { NagSuppressions } from 'cdk-nag';
33
+
34
+ /** codeburn sync fixed loopback callback ports (see codeburn src/sync/auth.ts). */
35
+ const CODEBURN_CALLBACK_PORTS = [19876, 19877, 19878];
36
+
37
+ export interface OtelCollectorConstructProps {
38
+ /** The prism-d1-ai-usage table — receiver writes SPAN# and OTEL#DAY# items. */
39
+ aiUsageTable: dynamodb.Table;
40
+ /** KMS key for the S3 archive bucket. */
41
+ kmsKey: kms.IKey;
42
+ /** VPC props spread applied to the receiver Lambda (matches stack pattern). */
43
+ lambdaVpcProps?: { vpc?: cdk.aws_ec2.IVpc; securityGroups?: cdk.aws_ec2.ISecurityGroup[] };
44
+ /** BYO IdP: OIDC issuer URL. When set, Cognito is NOT provisioned. */
45
+ externalIssuer?: string;
46
+ /** BYO IdP: OAuth client ID registered for codeburn (public client + PKCE). */
47
+ externalClientId?: string;
48
+ /** JWT claim used as the user identity key (default: username for Cognito, sub for BYO). */
49
+ identityClaim?: string;
50
+ }
51
+
52
+ export class OtelCollectorConstruct extends Construct {
53
+ public readonly httpApi: apigwv2.HttpApi;
54
+ public readonly archiveBucket: s3.Bucket;
55
+ public readonly userPool?: cognito.UserPool;
56
+ public readonly userPoolClient?: cognito.UserPoolClient;
57
+
58
+ constructor(scope: Construct, id: string, props: OtelCollectorConstructProps) {
59
+ super(scope, id);
60
+
61
+ const byoIdp = !!props.externalIssuer;
62
+ if (byoIdp && !props.externalClientId) {
63
+ throw new Error('otelClientId is required when otelIssuer is set');
64
+ }
65
+
66
+ // -------------------------------------------------------
67
+ // OIDC provider — Cognito (default) or BYO issuer
68
+ // -------------------------------------------------------
69
+ let issuer: string;
70
+ let clientId: string;
71
+ let identityClaim: string;
72
+
73
+ if (byoIdp) {
74
+ issuer = props.externalIssuer!.replace(/\/$/, '');
75
+ clientId = props.externalClientId!;
76
+ identityClaim = props.identityClaim ?? 'sub';
77
+ } else {
78
+ // Admin-create-user only (no self-signup); username = email so DDB keys
79
+ // line up with the USER#<email> key convention. We do NOT use
80
+ // signInAliases: { email: true } because that generates a random UUID
81
+ // as the internal username — the access token's `username` claim would
82
+ // carry the UUID, not the email. Instead, admins create users with
83
+ // --username dev@example.com and the `username` claim = the email.
84
+ this.userPool = new cognito.UserPool(this, 'UserPool', {
85
+ userPoolName: 'prism-d1-otel-users',
86
+ selfSignUpEnabled: false,
87
+ passwordPolicy: {
88
+ minLength: 12,
89
+ requireLowercase: true,
90
+ requireUppercase: true,
91
+ requireDigits: true,
92
+ requireSymbols: true,
93
+ },
94
+ advancedSecurityMode: cognito.AdvancedSecurityMode.ENFORCED,
95
+ featurePlan: cognito.FeaturePlan.PLUS,
96
+ removalPolicy: cdk.RemovalPolicy.RETAIN,
97
+ });
98
+
99
+ // Hosted UI domain — prefix must be globally unique per region.
100
+ this.userPool.addDomain('Domain', {
101
+ cognitoDomain: { domainPrefix: `prism-d1-otel-${cdk.Aws.ACCOUNT_ID}` },
102
+ });
103
+
104
+ // Public client (no secret) — codeburn does Authorization Code + PKCE
105
+ // with loopback redirects. Cognito allows http:// for localhost, 127.0.0.1,
106
+ // and [::1] (per CreateUserPoolClient API docs). codeburn uses 127.0.0.1.
107
+ const callbackUrls = CODEBURN_CALLBACK_PORTS.map(
108
+ (port) => `http://127.0.0.1:${port}/callback`,
109
+ );
110
+ this.userPoolClient = this.userPool.addClient('CodeburnClient', {
111
+ userPoolClientName: 'codeburn-sync',
112
+ generateSecret: false,
113
+ authFlows: { userSrp: true },
114
+ oAuth: {
115
+ flows: { authorizationCodeGrant: true },
116
+ scopes: [cognito.OAuthScope.OPENID, cognito.OAuthScope.EMAIL, cognito.OAuthScope.PROFILE],
117
+ callbackUrls,
118
+ },
119
+ preventUserExistenceErrors: true,
120
+ accessTokenValidity: cdk.Duration.hours(1),
121
+ refreshTokenValidity: cdk.Duration.days(30),
122
+ });
123
+
124
+ issuer = `https://cognito-idp.${cdk.Aws.REGION}.amazonaws.com/${this.userPool.userPoolId}`;
125
+ clientId = this.userPoolClient.userPoolClientId;
126
+ // Cognito ACCESS tokens carry `username` (no email claim) — with
127
+ // email-alias sign-in and admin-created users, username == email.
128
+ identityClaim = props.identityClaim ?? 'username';
129
+ }
130
+
131
+ // -------------------------------------------------------
132
+ // S3 archive — raw OTLP batches, the external consumption contract
133
+ // -------------------------------------------------------
134
+ this.archiveBucket = new s3.Bucket(this, 'ArchiveBucket', {
135
+ encryption: s3.BucketEncryption.KMS,
136
+ encryptionKey: props.kmsKey,
137
+ blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
138
+ enforceSSL: true,
139
+ removalPolicy: cdk.RemovalPolicy.RETAIN,
140
+ lifecycleRules: [{
141
+ id: 'expire-raw-otlp',
142
+ expiration: cdk.Duration.days(365),
143
+ }],
144
+ });
145
+
146
+ // -------------------------------------------------------
147
+ // Receiver Lambda — discovery doc + OTLP traces ingestion
148
+ // -------------------------------------------------------
149
+ const receiver = new lambda.Function(this, 'Receiver', {
150
+ functionName: 'prism-d1-otel-receiver',
151
+ runtime: lambda.Runtime.NODEJS_22_X,
152
+ handler: 'otel-receiver.handler',
153
+ ...(props.lambdaVpcProps ?? {}),
154
+ code: lambda.Code.fromAsset(path.join(__dirname, '..', 'lambda'), {
155
+ bundling: {
156
+ image: lambda.Runtime.NODEJS_22_X.bundlingImage,
157
+ command: [
158
+ 'bash', '-c',
159
+ [
160
+ 'npm init -y > /dev/null 2>&1',
161
+ 'npm install --save @aws-sdk/client-dynamodb @aws-sdk/client-s3 esbuild > /dev/null 2>&1',
162
+ 'npx esbuild otel-receiver.ts --bundle --platform=node --target=node22 --outfile=/asset-output/otel-receiver.js --external:@aws-sdk/*',
163
+ ].join(' && '),
164
+ ],
165
+ local: {
166
+ tryBundle(outputDir: string): boolean {
167
+ try {
168
+ const { execSync } = require('child_process');
169
+ execSync(
170
+ `npx esbuild ${path.join(__dirname, '..', 'lambda', 'otel-receiver.ts')} --bundle --platform=node --target=node22 --outfile=${path.join(outputDir, 'otel-receiver.js')} --external:@aws-sdk/*`,
171
+ { stdio: 'pipe' },
172
+ );
173
+ return true;
174
+ } catch {
175
+ return false;
176
+ }
177
+ },
178
+ },
179
+ },
180
+ }),
181
+ timeout: cdk.Duration.seconds(60),
182
+ memorySize: 512,
183
+ environment: {
184
+ AI_USAGE_TABLE: props.aiUsageTable.tableName,
185
+ ARCHIVE_BUCKET: this.archiveBucket.bucketName,
186
+ IDENTITY_CLAIM: identityClaim,
187
+ OIDC_ISSUER: issuer,
188
+ OIDC_CLIENT_ID: clientId,
189
+ MAX_BATCH_SIZE: '1000',
190
+ SPAN_TTL_DAYS: '90',
191
+ },
192
+ logRetention: logs.RetentionDays.ONE_MONTH,
193
+ description: 'Receives codeburn sync OTLP traces: S3 archive + per-user span/daily-aggregate rows',
194
+ });
195
+
196
+ props.aiUsageTable.grantReadWriteData(receiver);
197
+ this.archiveBucket.grantPut(receiver);
198
+ props.kmsKey.grantEncryptDecrypt(receiver);
199
+
200
+ // -------------------------------------------------------
201
+ // HTTP API — discovery (public) + traces (JWT)
202
+ // -------------------------------------------------------
203
+ this.httpApi = new apigwv2.HttpApi(this, 'Api', {
204
+ apiName: 'prism-d1-otel-collector',
205
+ description: 'PRISM D1 OTEL collector for codeburn sync',
206
+ });
207
+
208
+ const integration = new HttpLambdaIntegration('ReceiverIntegration', receiver);
209
+
210
+ // HTTP API JWT authorizers validate the `aud` claim, or `client_id` for
211
+ // Cognito access tokens — both paths work with jwtAudience = [clientId].
212
+ const authorizer = new HttpJwtAuthorizer('OtelJwtAuthorizer', issuer, {
213
+ jwtAudience: [clientId],
214
+ });
215
+
216
+ // Discovery doc — unauthenticated by design (it only exposes issuer +
217
+ // client_id, both public values in an OAuth public-client flow).
218
+ this.httpApi.addRoutes({
219
+ path: '/.well-known/codeburn-export.json',
220
+ methods: [apigwv2.HttpMethod.GET],
221
+ integration,
222
+ });
223
+
224
+ this.httpApi.addRoutes({
225
+ path: '/v1/traces',
226
+ methods: [apigwv2.HttpMethod.POST],
227
+ integration,
228
+ authorizer,
229
+ });
230
+
231
+ // Access logging on the default stage (AwsSolutions-APIG1).
232
+ const accessLogGroup = new logs.LogGroup(this, 'ApiAccessLogs', {
233
+ logGroupName: '/aws/apigateway/prism-d1-otel-collector',
234
+ retention: logs.RetentionDays.ONE_MONTH,
235
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
236
+ });
237
+ const defaultStage = this.httpApi.defaultStage!.node.defaultChild as apigwv2.CfnStage;
238
+ defaultStage.accessLogSettings = {
239
+ destinationArn: accessLogGroup.logGroupArn,
240
+ format: JSON.stringify({
241
+ requestId: '$context.requestId',
242
+ ip: '$context.identity.sourceIp',
243
+ requestTime: '$context.requestTime',
244
+ httpMethod: '$context.httpMethod',
245
+ path: '$context.path',
246
+ status: '$context.status',
247
+ responseLength: '$context.responseLength',
248
+ userAgent: '$context.identity.userAgent',
249
+ }),
250
+ };
251
+
252
+ // -------------------------------------------------------
253
+ // cdk-nag suppressions (with evidence)
254
+ // -------------------------------------------------------
255
+ NagSuppressions.addResourceSuppressions(receiver, [
256
+ {
257
+ id: 'AwsSolutions-IAM5',
258
+ reason: 'grantPut generates s3:Abort* + bucket/* wildcard scoped to the single OTLP archive bucket',
259
+ appliesTo: ['Action::s3:Abort*', { regex: '/^Resource::<OtelCollectorArchiveBucket.*\\.Arn>\\/\\*$/g' }],
260
+ },
261
+ {
262
+ id: 'AwsSolutions-IAM5',
263
+ reason: 'grantReadWriteData generates a wildcard for the AI-usage table GSI index ARNs',
264
+ appliesTo: [{ regex: '/^Resource::<AiUsageTable.*\\.Arn>\\/index\\/\\*$/g' }],
265
+ },
266
+ ], true);
267
+ NagSuppressions.addResourceSuppressions(this.httpApi, [
268
+ {
269
+ id: 'AwsSolutions-APIG4',
270
+ reason: 'The codeburn discovery doc route is unauthenticated by design — it only publishes the OIDC issuer and public client_id (both non-secret in an OAuth public-client PKCE flow). The traces route is JWT-authorized.',
271
+ },
272
+ ], true);
273
+ NagSuppressions.addResourceSuppressions(this.archiveBucket, [
274
+ {
275
+ id: 'AwsSolutions-S1',
276
+ reason: 'Telemetry archive bucket for a sample project; access is limited to the receiver Lambda (put) and account principals. Enable S3 server access logging or CloudTrail data events for production hardening.',
277
+ },
278
+ ]);
279
+ if (this.userPool) {
280
+ NagSuppressions.addResourceSuppressions(this.userPool, [
281
+ {
282
+ id: 'AwsSolutions-COG2',
283
+ reason: 'MFA is not required for the codeburn telemetry-push user pool: users are admin-created, the client is scoped to telemetry writes only, and MFA on a CLI OIDC device flow adds friction disproportionate to the data sensitivity. Enable MFA for production hardening.',
284
+ },
285
+ ]);
286
+ }
287
+
288
+ // -------------------------------------------------------
289
+ // Outputs — everything needed to run `codeburn sync setup <url>`
290
+ // -------------------------------------------------------
291
+ new cdk.CfnOutput(this, 'OtelCollectorUrl', {
292
+ value: this.httpApi.apiEndpoint,
293
+ description: 'Run: codeburn sync setup <this URL>',
294
+ });
295
+ if (this.userPool) {
296
+ new cdk.CfnOutput(this, 'OtelUserPoolId', {
297
+ value: this.userPool.userPoolId,
298
+ description: 'Create users: aws cognito-idp admin-create-user --user-pool-id <this> --username <email>',
299
+ });
300
+ }
301
+ }
302
+ }
@@ -46,6 +46,11 @@ export class PrismVpcConstruct extends Construct {
46
46
  service: ec2.GatewayVpcEndpointAwsService.DYNAMODB,
47
47
  });
48
48
 
49
+ // --- Gateway endpoint: S3 (free; used by the OTEL receiver archive writes) ---
50
+ this.vpc.addGatewayEndpoint('S3Endpoint', {
51
+ service: ec2.GatewayVpcEndpointAwsService.S3,
52
+ });
53
+
49
54
  // --- Interface endpoints ---
50
55
  const interfaceEndpoints = [
51
56
  { id: 'EventBridgeEndpoint', service: ec2.InterfaceVpcEndpointAwsService.EVENTBRIDGE },
@@ -151,6 +151,7 @@ const EVENTS_TABLE = process.env.EVENTS_TABLE!;
151
151
  const METADATA_TABLE = process.env.METADATA_TABLE!;
152
152
  const METRIC_NAMESPACE = process.env.METRIC_NAMESPACE ?? 'PRISM/D1/Velocity';
153
153
 
154
+
154
155
  // ---- Handler ----
155
156
 
156
157
  export async function handler(event: EventBridgeEvent): Promise<void> {
@@ -0,0 +1,369 @@
1
+ /**
2
+ * PRISM D1 — OTLP receiver for codeburn sync.
3
+ *
4
+ * Serves two routes on the OTEL collector HTTP API:
5
+ * GET /.well-known/codeburn-export.json — discovery doc (no auth)
6
+ * POST /v1/traces — OTLP/HTTP JSON traces (JWT-authorized)
7
+ *
8
+ * Trace flow: validate (JWT done by API Gateway) → archive raw OTLP batch to S3
9
+ * (external contract — standard OTLP JSON, Athena/replay-friendly) → per-span
10
+ * conditional DynamoDB write (dedup gate) → daily aggregate ADD (only for
11
+ * newly-seen spans, bucketed by SPAN date, not arrival date).
12
+ *
13
+ * Item shapes in the AI-usage table:
14
+ * pk=USER#<identity> sk=SPAN#<timestamp>#<spanId> raw span, TTL 90d
15
+ * pk=USER#<identity> sk=OTEL#DAY#<yyyy-mm-dd>#<tool> daily aggregate
16
+ */
17
+
18
+ import {
19
+ DynamoDBClient,
20
+ PutItemCommand,
21
+ UpdateItemCommand,
22
+ ConditionalCheckFailedException,
23
+ } from '@aws-sdk/client-dynamodb';
24
+ import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
25
+ import { randomUUID } from 'crypto';
26
+
27
+ const dynamoClient = new DynamoDBClient({});
28
+ const s3Client = new S3Client({});
29
+
30
+ const AI_USAGE_TABLE = process.env.AI_USAGE_TABLE || 'prism-d1-ai-usage';
31
+ const ARCHIVE_BUCKET = process.env.ARCHIVE_BUCKET || '';
32
+ const IDENTITY_CLAIM = process.env.IDENTITY_CLAIM || 'username';
33
+ const OIDC_ISSUER = process.env.OIDC_ISSUER || '';
34
+ const OIDC_CLIENT_ID = process.env.OIDC_CLIENT_ID || '';
35
+ const MAX_BATCH_SIZE = Number(process.env.MAX_BATCH_SIZE || '1000');
36
+ const SPAN_TTL_DAYS = Number(process.env.SPAN_TTL_DAYS || '90');
37
+
38
+ /** codeburn provider names → PRISM tool names. */
39
+ const PROVIDER_TO_TOOL: Record<string, string> = {
40
+ claude: 'claude-code',
41
+ kiro: 'kiro',
42
+ cursor: 'cursor',
43
+ codex: 'codex',
44
+ copilot: 'copilot',
45
+ };
46
+
47
+ // ---- Types (API Gateway HTTP API v2 proxy + OTLP JSON) ----
48
+
49
+ interface HttpApiEvent {
50
+ rawPath: string;
51
+ requestContext: {
52
+ http: { method: string; path: string };
53
+ authorizer?: { jwt?: { claims?: Record<string, unknown> } };
54
+ };
55
+ body?: string;
56
+ isBase64Encoded?: boolean;
57
+ }
58
+
59
+ interface HttpApiResponse {
60
+ statusCode: number;
61
+ headers: Record<string, string>;
62
+ body: string;
63
+ }
64
+
65
+ type OtlpValue =
66
+ | { stringValue?: string; intValue?: string | number; doubleValue?: number; boolValue?: boolean };
67
+
68
+ interface OtlpAttribute {
69
+ key: string;
70
+ value: OtlpValue;
71
+ }
72
+
73
+ interface OtlpSpan {
74
+ traceId?: string;
75
+ spanId?: string;
76
+ name?: string;
77
+ startTimeUnixNano?: string;
78
+ attributes?: OtlpAttribute[];
79
+ }
80
+
81
+ interface OtlpPayload {
82
+ resourceSpans?: Array<{
83
+ resource?: { attributes?: OtlpAttribute[] };
84
+ scopeSpans?: Array<{ spans?: OtlpSpan[] }>;
85
+ }>;
86
+ }
87
+
88
+ interface ParsedSpan {
89
+ spanId: string;
90
+ timestamp: string; // ISO from span start time
91
+ tool: string;
92
+ model: string;
93
+ inputTokens: number;
94
+ outputTokens: number;
95
+ costUsd: number;
96
+ project: string;
97
+ costEstimated: boolean;
98
+ deviceId: string;
99
+ }
100
+
101
+ // ---- Helpers ----
102
+
103
+ function jsonResponse(statusCode: number, body: unknown): HttpApiResponse {
104
+ return {
105
+ statusCode,
106
+ headers: { 'Content-Type': 'application/json' },
107
+ body: JSON.stringify(body),
108
+ };
109
+ }
110
+
111
+ function attrMap(attrs: OtlpAttribute[] | undefined): Map<string, OtlpValue> {
112
+ const m = new Map<string, OtlpValue>();
113
+ for (const a of attrs ?? []) {
114
+ if (a && typeof a.key === 'string' && a.value) m.set(a.key, a.value);
115
+ }
116
+ return m;
117
+ }
118
+
119
+ function str(v: OtlpValue | undefined): string {
120
+ return typeof v?.stringValue === 'string' ? v.stringValue : '';
121
+ }
122
+
123
+ function num(v: OtlpValue | undefined): number {
124
+ if (v?.intValue !== undefined) {
125
+ const n = Number(v.intValue);
126
+ return Number.isFinite(n) ? n : 0;
127
+ }
128
+ if (typeof v?.doubleValue === 'number' && Number.isFinite(v.doubleValue)) return v.doubleValue;
129
+ return 0;
130
+ }
131
+
132
+ function bool(v: OtlpValue | undefined): boolean {
133
+ return v?.boolValue === true;
134
+ }
135
+
136
+ /** Convert OTLP unix-nano string to ISO timestamp; empty string if invalid. */
137
+ function nanoToIso(nano: string | undefined): string {
138
+ if (!nano || !/^\d+$/.test(nano)) return '';
139
+ try {
140
+ const ms = Number(BigInt(nano) / 1_000_000n);
141
+ if (!Number.isFinite(ms) || ms <= 0) return '';
142
+ const d = new Date(ms);
143
+ return isNaN(d.getTime()) ? '' : d.toISOString();
144
+ } catch {
145
+ return '';
146
+ }
147
+ }
148
+
149
+ /** Resolve caller identity from JWT claims (validated by the API Gateway authorizer). */
150
+ function resolveIdentity(event: HttpApiEvent): string | null {
151
+ const claims = event.requestContext.authorizer?.jwt?.claims;
152
+ if (!claims) return null;
153
+ for (const claim of [IDENTITY_CLAIM, 'username', 'email', 'sub']) {
154
+ const v = claims[claim];
155
+ if (typeof v === 'string' && v.trim()) return v.trim().toLowerCase();
156
+ }
157
+ return null;
158
+ }
159
+
160
+ /** Extract and sanity-check spans from an OTLP payload. Returns spans + rejected count. */
161
+ export function parseOtlpSpans(payload: OtlpPayload): { spans: ParsedSpan[]; rejected: number } {
162
+ const spans: ParsedSpan[] = [];
163
+ let rejected = 0;
164
+
165
+ for (const rs of payload.resourceSpans ?? []) {
166
+ const resourceAttrs = attrMap(rs.resource?.attributes);
167
+ const deviceId = str(resourceAttrs.get('codeburn.device_id')).slice(0, 64);
168
+
169
+ for (const ss of rs.scopeSpans ?? []) {
170
+ for (const span of ss.spans ?? []) {
171
+ const attrs = attrMap(span.attributes);
172
+ const spanId = typeof span.spanId === 'string' ? span.spanId : '';
173
+ const timestamp = nanoToIso(span.startTimeUnixNano);
174
+ const provider = str(attrs.get('ai.provider'));
175
+
176
+ // Minimum viable span: identity key parts must be present and sane.
177
+ if (!/^[0-9a-f]{16}$/i.test(spanId) || !timestamp || !provider) {
178
+ rejected++;
179
+ continue;
180
+ }
181
+
182
+ const inputTokens = num(attrs.get('ai.input_tokens'));
183
+ const outputTokens = num(attrs.get('ai.output_tokens'));
184
+ const costUsd = num(attrs.get('ai.cost_usd'));
185
+ // Clamp: reject absurd values (mirrors the CI trailer clamps).
186
+ if (
187
+ inputTokens < 0 || outputTokens < 0 || costUsd < 0 ||
188
+ inputTokens > 100_000_000 || outputTokens > 100_000_000 || costUsd > 10_000
189
+ ) {
190
+ rejected++;
191
+ continue;
192
+ }
193
+
194
+ spans.push({
195
+ spanId: spanId.toLowerCase(),
196
+ timestamp,
197
+ tool: PROVIDER_TO_TOOL[provider] ?? provider.slice(0, 32),
198
+ model: str(attrs.get('ai.model')).slice(0, 128),
199
+ inputTokens,
200
+ outputTokens,
201
+ costUsd,
202
+ project: str(attrs.get('ai.project')).slice(0, 256),
203
+ costEstimated: bool(attrs.get('ai.cost_estimated')),
204
+ deviceId,
205
+ });
206
+ }
207
+ }
208
+ }
209
+
210
+ return { spans, rejected };
211
+ }
212
+
213
+ // ---- Route: discovery doc ----
214
+
215
+ function handleDiscovery(): HttpApiResponse {
216
+ return jsonResponse(200, {
217
+ version: 1,
218
+ issuer: OIDC_ISSUER,
219
+ client_id: OIDC_CLIENT_ID,
220
+ scopes: ['openid', 'email', 'profile'],
221
+ traces_path: '/v1/traces',
222
+ max_batch_size: MAX_BATCH_SIZE,
223
+ });
224
+ }
225
+
226
+ // ---- Route: traces ----
227
+
228
+ async function archiveToS3(rawBody: string): Promise<void> {
229
+ if (!ARCHIVE_BUCKET) return;
230
+ const now = new Date();
231
+ const dt = now.toISOString().slice(0, 10);
232
+ const key = `otlp/dt=${dt}/${now.toISOString().replace(/[:.]/g, '-')}-${randomUUID()}.json`;
233
+ await s3Client.send(new PutObjectCommand({
234
+ Bucket: ARCHIVE_BUCKET,
235
+ Key: key,
236
+ Body: rawBody,
237
+ ContentType: 'application/json',
238
+ }));
239
+ }
240
+
241
+ /** Conditional raw-span write. Returns true if the span is NEW (write succeeded). */
242
+ async function writeSpanIfNew(user: string, s: ParsedSpan): Promise<boolean> {
243
+ const ttl = Math.floor(Date.now() / 1000) + SPAN_TTL_DAYS * 24 * 60 * 60;
244
+ try {
245
+ await dynamoClient.send(new PutItemCommand({
246
+ TableName: AI_USAGE_TABLE,
247
+ Item: {
248
+ pk: { S: `USER#${user}` },
249
+ sk: { S: `SPAN#${s.timestamp}#${s.spanId}` },
250
+ record_type: { S: 'OTEL_SPAN' },
251
+ tool: { S: s.tool },
252
+ model: { S: s.model },
253
+ input_tokens: { N: String(s.inputTokens) },
254
+ output_tokens: { N: String(s.outputTokens) },
255
+ cost_usd: { N: String(s.costUsd) },
256
+ project: { S: s.project },
257
+ device_id: { S: s.deviceId },
258
+ cost_estimated: { BOOL: s.costEstimated },
259
+ timestamp: { S: s.timestamp },
260
+ ttl: { N: String(ttl) },
261
+ },
262
+ // Dedup gate: deterministic span IDs make retried batches no-ops.
263
+ ConditionExpression: 'attribute_not_exists(pk)',
264
+ }));
265
+ return true;
266
+ } catch (e) {
267
+ if (e instanceof ConditionalCheckFailedException) return false;
268
+ throw e;
269
+ }
270
+ }
271
+
272
+ /** ADD-increment the daily aggregate for a newly-seen span (bucketed by SPAN date). */
273
+ async function bumpDailyAggregate(user: string, s: ParsedSpan): Promise<void> {
274
+ const day = s.timestamp.slice(0, 10);
275
+ await dynamoClient.send(new UpdateItemCommand({
276
+ TableName: AI_USAGE_TABLE,
277
+ Key: {
278
+ pk: { S: `USER#${user}` },
279
+ sk: { S: `OTEL#DAY#${day}#${s.tool}` },
280
+ },
281
+ UpdateExpression:
282
+ 'ADD input_tokens :in, output_tokens :out, cost_usd :cost, call_count :one ' +
283
+ 'SET record_type = :rt, tool = :tool, #day = :day, updated_at = :now',
284
+ ExpressionAttributeNames: { '#day': 'day' },
285
+ ExpressionAttributeValues: {
286
+ ':in': { N: String(s.inputTokens) },
287
+ ':out': { N: String(s.outputTokens) },
288
+ ':cost': { N: String(s.costUsd) },
289
+ ':one': { N: '1' },
290
+ ':rt': { S: 'OTEL_DAY' },
291
+ ':tool': { S: s.tool },
292
+ ':day': { S: day },
293
+ ':now': { S: new Date().toISOString() },
294
+ },
295
+ }));
296
+ }
297
+
298
+ /** Process spans with bounded concurrency. Returns count of newly-written spans. */
299
+ async function processSpans(user: string, spans: ParsedSpan[]): Promise<number> {
300
+ const CONCURRENCY = 20;
301
+ let written = 0;
302
+ for (let i = 0; i < spans.length; i += CONCURRENCY) {
303
+ const chunk = spans.slice(i, i + CONCURRENCY);
304
+ const results = await Promise.all(chunk.map(async (s) => {
305
+ const isNew = await writeSpanIfNew(user, s);
306
+ if (isNew) await bumpDailyAggregate(user, s);
307
+ return isNew;
308
+ }));
309
+ written += results.filter(Boolean).length;
310
+ }
311
+ return written;
312
+ }
313
+
314
+ async function handleTraces(event: HttpApiEvent): Promise<HttpApiResponse> {
315
+ const user = resolveIdentity(event);
316
+ if (!user) {
317
+ return jsonResponse(401, { message: 'No resolvable identity claim in token' });
318
+ }
319
+
320
+ const rawBody = event.isBase64Encoded
321
+ ? Buffer.from(event.body ?? '', 'base64').toString('utf-8')
322
+ : (event.body ?? '');
323
+
324
+ let payload: OtlpPayload;
325
+ try {
326
+ payload = JSON.parse(rawBody) as OtlpPayload;
327
+ } catch {
328
+ return jsonResponse(400, { message: 'Body is not valid JSON' });
329
+ }
330
+
331
+ const { spans, rejected } = parseOtlpSpans(payload);
332
+
333
+ if (spans.length > MAX_BATCH_SIZE) {
334
+ return jsonResponse(400, { message: `Batch exceeds max_batch_size (${MAX_BATCH_SIZE})` });
335
+ }
336
+
337
+ // Archive the raw batch first — the S3 OTLP archive is the external contract.
338
+ // Archive failures are fatal (client retries the batch; dedup gate makes it safe).
339
+ await archiveToS3(rawBody);
340
+
341
+ const written = await processSpans(user, spans);
342
+ console.log(
343
+ `[otel-receiver] user=${user} received=${spans.length + rejected} accepted=${spans.length} ` +
344
+ `new=${written} duplicates=${spans.length - written} rejected=${rejected}`,
345
+ );
346
+
347
+ // OTLP/HTTP success response; report malformed spans via partialSuccess.
348
+ if (rejected > 0) {
349
+ return jsonResponse(200, {
350
+ partialSuccess: { rejectedSpans: rejected, errorMessage: 'Spans missing required ai.* attributes or failed validation' },
351
+ });
352
+ }
353
+ return jsonResponse(200, {});
354
+ }
355
+
356
+ // ---- Handler ----
357
+
358
+ export async function handler(event: HttpApiEvent): Promise<HttpApiResponse> {
359
+ const method = event.requestContext.http.method;
360
+ const path = event.rawPath;
361
+
362
+ if (method === 'GET' && path === '/.well-known/codeburn-export.json') {
363
+ return handleDiscovery();
364
+ }
365
+ if (method === 'POST' && path === '/v1/traces') {
366
+ return handleTraces(event);
367
+ }
368
+ return jsonResponse(404, { message: 'Not found' });
369
+ }
@@ -13,15 +13,18 @@ import * as ec2 from 'aws-cdk-lib/aws-ec2';
13
13
  import { PrismVpcConstruct } from './constructs/prism-vpc-construct';
14
14
  import { GuardrailEnforcerConstruct } from './constructs/guardrail-enforcer-construct';
15
15
  import { SecurityAgentConstruct } from './constructs/security-agent-construct';
16
+ import { OtelCollectorConstruct } from './constructs/otel-collector-construct';
16
17
  import { NagSuppressions } from 'cdk-nag';
17
18
 
18
19
  export class MetricsPipelineStack extends cdk.Stack {
19
20
  public readonly eventBus: events.EventBus;
20
21
  public readonly eventsTable: dynamodb.Table;
22
+ public readonly aiUsageTable: dynamodb.Table;
21
23
  public readonly metadataTable: dynamodb.Table;
22
24
  public readonly kmsKey: kms.Key;
23
25
  public readonly guardrail: BedrockGuardrailConstruct;
24
26
  public readonly securityAgent?: SecurityAgentConstruct;
27
+ public readonly otelCollector?: OtelCollectorConstruct;
25
28
 
26
29
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
27
30
  super(scope, id, props);
@@ -127,6 +130,38 @@ export class MetricsPipelineStack extends cdk.Stack {
127
130
  encryptionKey: prismKmsKey,
128
131
  });
129
132
 
133
+ // -------------------------------------------------------
134
+ // DynamoDB AI-usage table — user-keyed, KMS encrypted
135
+ // pk = USER#<email>
136
+ // sk = COMMIT#<ts>#<sha>#<tool> | SPAN#<ts>#<spanId> | OTEL#DAY#<date>#<tool>
137
+ // Sparse GSIs (only commit-level items set them) invert the user key so the
138
+ // same table answers by-repo / by-PR / by-commit / global-by-date.
139
+ // -------------------------------------------------------
140
+ this.aiUsageTable = new dynamodb.Table(this, 'AiUsageTable', {
141
+ tableName: 'prism-d1-ai-usage',
142
+ partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING },
143
+ sortKey: { name: 'sk', type: dynamodb.AttributeType.STRING },
144
+ billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
145
+ pointInTimeRecoverySpecification: { pointInTimeRecoveryEnabled: true },
146
+ removalPolicy: cdk.RemovalPolicy.RETAIN,
147
+ timeToLiveAttribute: 'ttl',
148
+ encryption: dynamodb.TableEncryption.CUSTOMER_MANAGED,
149
+ encryptionKey: prismKmsKey,
150
+ });
151
+ for (const [indexName, pkAttr, skAttr] of [
152
+ ['by-repo', 'gsi_repo', 'gsi_repo_sk'],
153
+ ['by-pr', 'gsi_pr', 'gsi_pr_sk'],
154
+ ['by-commit', 'gsi_commit', 'gsi_commit_sk'],
155
+ ['by-date', 'gsi_date', 'gsi_date_sk'],
156
+ ] as const) {
157
+ this.aiUsageTable.addGlobalSecondaryIndex({
158
+ indexName,
159
+ partitionKey: { name: pkAttr, type: dynamodb.AttributeType.STRING },
160
+ sortKey: { name: skAttr, type: dynamodb.AttributeType.STRING },
161
+ projectionType: dynamodb.ProjectionType.ALL,
162
+ });
163
+ }
164
+
130
165
  // -------------------------------------------------------
131
166
  // VPC for Lambda isolation (Pillar 6)
132
167
  // Opt out with: cdk deploy -c skipVpc=true
@@ -253,6 +288,25 @@ export class MetricsPipelineStack extends cdk.Stack {
253
288
  // -------------------------------------------------------
254
289
  this.guardrail = new BedrockGuardrailConstruct(this, 'PrismGuardrail', createDefaultPrismGuardrailProps());
255
290
 
291
+ // -------------------------------------------------------
292
+ // OTEL Collector (opt-in — server side of `codeburn sync`)
293
+ // Enable with: npx cdk deploy --context enableOtelCollector=true
294
+ // BYO IdP: -c otelIssuer=... -c otelClientId=... [-c otelIdentityClaim=email]
295
+ // Per-user AI usage flows directly from codeburn sync to the
296
+ // ai-usage table (spans + daily aggregates).
297
+ // -------------------------------------------------------
298
+ const enableOtelCollector = this.node.tryGetContext('enableOtelCollector') === 'true';
299
+ if (enableOtelCollector) {
300
+ this.otelCollector = new OtelCollectorConstruct(this, 'OtelCollector', {
301
+ aiUsageTable: this.aiUsageTable,
302
+ kmsKey: prismKmsKey,
303
+ lambdaVpcProps,
304
+ externalIssuer: this.node.tryGetContext('otelIssuer') as string | undefined,
305
+ externalClientId: this.node.tryGetContext('otelClientId') as string | undefined,
306
+ identityClaim: this.node.tryGetContext('otelIdentityClaim') as string | undefined,
307
+ });
308
+ }
309
+
256
310
  // -------------------------------------------------------
257
311
  // AWS Security Agent (opt-in — requires Security Agent access)
258
312
  // Enable with: npx cdk deploy --context enableSecurityAgent=true
@@ -681,7 +735,7 @@ export class MetricsPipelineStack extends cdk.Stack {
681
735
  {
682
736
  id: 'AwsSolutions-IAM5',
683
737
  reason: 'CDK grantReadData on DynamoDB generates wildcard for GSI index ARNs via token reference',
684
- appliesTo: ['Resource::<EventsTableD24865E5.Arn>/index/*'],
738
+ appliesTo: ['Resource::<EventsTableD24865E5.Arn>/index/*', 'Resource::<AiUsageTable79F37CE0.Arn>/index/*'],
685
739
  },
686
740
  { id: 'AwsSolutions-L1', reason: 'All Lambdas use nodejs22.x which is the latest Node.js runtime available' },
687
741
  ]);
@@ -1 +1 @@
1
- {"version":3,"file":"commit-trailers.d.ts","sourceRoot":"","sources":["../../../../src/commands/git/commit-trailers.ts"],"names":[],"mappings":";;;;;;iBA4JqB;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;;AAP/E,wBAkGE"}
1
+ {"version":3,"file":"commit-trailers.d.ts","sourceRoot":"","sources":["../../../../src/commands/git/commit-trailers.ts"],"names":[],"mappings":";;;;;;iBA4JqB;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;;AAP/E,wBAgGE"}
@@ -3,7 +3,6 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
3
3
  import { resolve, basename } from 'node:path';
4
4
  import { homedir } from 'node:os';
5
5
  import { collectKiroCli } from '../parse-code-tool/kiro-cli.js';
6
- import { collectKiroIde } from '../parse-code-tool/kiro-ide.js';
7
6
  const DEFAULT_CLAUDE_MODEL = 'us.anthropic.claude-sonnet-4-5-20250929-v1:0';
8
7
  function gitRoot(explicit) {
9
8
  if (explicit)
@@ -89,29 +88,32 @@ function runCodeburn(projectFilter, provider) {
89
88
  /** Collect cumulative token usage for the given tool + project. */
90
89
  async function collectUsage(tool, projectBasename, projectFilter) {
91
90
  if (tool === 'kiro') {
91
+ // Kiro usage is tracked by codeburn natively (provider: kiro). codeburn reads
92
+ // Kiro's session files and provides a real-time cumulative view, unlike the
93
+ // prism-cli kiro-ide parser which only sees stale on-disk snapshots.
92
94
  let out = null;
93
95
  if (process.env.KIRO_SESSION_ID) {
94
96
  out = await collectKiroCli(process.env.KIRO_SESSION_ID, projectBasename);
95
97
  }
96
- if (!out || out.overview.calls === 0) {
97
- out = await collectKiroIde(projectBasename);
98
- }
99
- return out;
98
+ if (out && out.overview.calls > 0)
99
+ return { data: out, source: 'kiro-cli' };
100
+ out = runCodeburn(projectFilter, 'kiro');
101
+ if (!out || out.overview.calls === 0)
102
+ out = runCodeburn(projectBasename, 'kiro');
103
+ if (out && out.overview.calls > 0)
104
+ return { data: out, source: 'kiro' };
105
+ return null;
100
106
  }
101
- // cursor → codeburn with the cursor provider filter (codeburn natively tracks
102
- // Cursor usage). Isolating to --provider cursor keeps its snapshot delta from
103
- // being polluted by other providers' totals.
104
107
  if (tool === 'cursor') {
105
108
  let out = runCodeburn(projectFilter, 'cursor');
106
109
  if (!out || out.overview.calls === 0)
107
110
  out = runCodeburn(projectBasename, 'cursor');
108
- return out;
111
+ return out ? { data: out, source: 'cursor' } : null;
109
112
  }
110
- // claude-code / q-developer → codeburn (full-path slug, then basename fallback)
111
113
  let out = runCodeburn(projectFilter);
112
114
  if (!out || out.overview.calls === 0)
113
115
  out = runCodeburn(projectBasename);
114
- return out;
116
+ return out ? { data: out, source: tool } : null;
115
117
  }
116
118
  function sumTokens(o, key) {
117
119
  return (o.models || []).reduce((s, m) => s + (m[key] || 0), 0);
@@ -166,21 +168,18 @@ export default {
166
168
  let outputTokens = null;
167
169
  let cost = null;
168
170
  if (tool) {
169
- const usage = await collectUsage(tool, projectBasename, projectFilter);
170
- if (usage) {
171
+ const result = await collectUsage(tool, projectBasename, projectFilter);
172
+ if (result) {
173
+ const { data: usage, source: usageSource } = result;
171
174
  const curIn = sumTokens(usage, 'inputTokens');
172
175
  const curOut = sumTokens(usage, 'outputTokens');
173
176
  const curCost = usage.overview?.cost ?? 0;
174
177
  const trackerDir = resolve(homedir(), '.prism', 'tokentracker');
175
- // Snapshot baselines are keyed by (project, tool) so each tool's cumulative
176
- // usage is isolated. Mixing tools in a single file corrupts deltas because
177
- // their cumulative bases are not comparable — e.g. a per-session Kiro CLI
178
- // total vs a lifetime Kiro IDE total, or codeburn's real provider counts vs
179
- // char-estimated counts. Older un-keyed <project>.json files from before this
180
- // change are left orphaned (never read again); the first commit per
181
- // (project, tool) finds no baseline and correctly reports a 0 delta while
182
- // establishing the new baseline.
183
- const trackerFile = resolve(trackerDir, `${projectBasename}.${tool}.json`);
178
+ // Snapshot baselines are keyed by (project, source) — NOT just (project, tool).
179
+ // Kiro has two sources (kiro-cli per-session vs kiro-ide lifetime) with
180
+ // vastly different cumulative totals. Sharing a tracker file between them
181
+ // produces massive false deltas when the fallback path switches.
182
+ const trackerFile = resolve(trackerDir, `${projectBasename}.${usageSource}.json`);
184
183
  if (existsSync(trackerFile)) {
185
184
  try {
186
185
  const prev = JSON.parse(readFileSync(trackerFile, 'utf8'));
@@ -1 +1 @@
1
- {"version":3,"file":"commit-trailers.js","sourceRoot":"","sources":["../../../../src/commands/git/commit-trailers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"commit-trailers.js","sourceRoot":"","sources":["../../../../src/commands/git/commit-trailers.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prism-d1/cli",
3
- "version": "1.0.62",
3
+ "version": "1.0.65",
4
4
  "description": "PRISM D1 Velocity CLI — AI development lifecycle assessment tool",
5
5
  "author": "andklee",
6
6
  "engines": {