@exaudeus/workrail 3.64.0 → 3.65.0

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.
@@ -2472,6 +2472,96 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
2472
2472
  traceId: string;
2473
2473
  };
2474
2474
  timestampMs: number;
2475
+ }>, z.ZodObject<{
2476
+ v: z.ZodLiteral<1>;
2477
+ eventId: z.ZodString;
2478
+ eventIndex: z.ZodNumber;
2479
+ sessionId: z.ZodString;
2480
+ dedupeKey: z.ZodString;
2481
+ timestampMs: z.ZodNumber;
2482
+ } & {
2483
+ kind: z.ZodLiteral<"run_completed">;
2484
+ scope: z.ZodObject<{
2485
+ runId: z.ZodString;
2486
+ }, "strip", z.ZodTypeAny, {
2487
+ runId: string;
2488
+ }, {
2489
+ runId: string;
2490
+ }>;
2491
+ data: z.ZodEffects<z.ZodObject<{
2492
+ startGitSha: z.ZodNullable<z.ZodString>;
2493
+ endGitSha: z.ZodNullable<z.ZodString>;
2494
+ gitBranch: z.ZodNullable<z.ZodString>;
2495
+ agentCommitShas: z.ZodArray<z.ZodString, "many">;
2496
+ captureConfidence: z.ZodEnum<["high", "none"]>;
2497
+ durationMs: z.ZodOptional<z.ZodNumber>;
2498
+ }, "strip", z.ZodTypeAny, {
2499
+ startGitSha: string | null;
2500
+ endGitSha: string | null;
2501
+ gitBranch: string | null;
2502
+ agentCommitShas: string[];
2503
+ captureConfidence: "high" | "none";
2504
+ durationMs?: number | undefined;
2505
+ }, {
2506
+ startGitSha: string | null;
2507
+ endGitSha: string | null;
2508
+ gitBranch: string | null;
2509
+ agentCommitShas: string[];
2510
+ captureConfidence: "high" | "none";
2511
+ durationMs?: number | undefined;
2512
+ }>, {
2513
+ startGitSha: string | null;
2514
+ endGitSha: string | null;
2515
+ gitBranch: string | null;
2516
+ agentCommitShas: string[];
2517
+ captureConfidence: "high" | "none";
2518
+ durationMs?: number | undefined;
2519
+ }, {
2520
+ startGitSha: string | null;
2521
+ endGitSha: string | null;
2522
+ gitBranch: string | null;
2523
+ agentCommitShas: string[];
2524
+ captureConfidence: "high" | "none";
2525
+ durationMs?: number | undefined;
2526
+ }>;
2527
+ }, "strip", z.ZodTypeAny, {
2528
+ kind: "run_completed";
2529
+ v: 1;
2530
+ sessionId: string;
2531
+ eventIndex: number;
2532
+ eventId: string;
2533
+ dedupeKey: string;
2534
+ scope: {
2535
+ runId: string;
2536
+ };
2537
+ data: {
2538
+ startGitSha: string | null;
2539
+ endGitSha: string | null;
2540
+ gitBranch: string | null;
2541
+ agentCommitShas: string[];
2542
+ captureConfidence: "high" | "none";
2543
+ durationMs?: number | undefined;
2544
+ };
2545
+ timestampMs: number;
2546
+ }, {
2547
+ kind: "run_completed";
2548
+ v: 1;
2549
+ sessionId: string;
2550
+ eventIndex: number;
2551
+ eventId: string;
2552
+ dedupeKey: string;
2553
+ scope: {
2554
+ runId: string;
2555
+ };
2556
+ data: {
2557
+ startGitSha: string | null;
2558
+ endGitSha: string | null;
2559
+ gitBranch: string | null;
2560
+ agentCommitShas: string[];
2561
+ captureConfidence: "high" | "none";
2562
+ durationMs?: number | undefined;
2563
+ };
2564
+ timestampMs: number;
2475
2565
  }>]>, "many">;
2476
2566
  manifest: z.ZodArray<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
2477
2567
  v: z.ZodLiteral<1>;
@@ -5196,6 +5286,25 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
5196
5286
  traceId: string;
5197
5287
  };
5198
5288
  timestampMs: number;
5289
+ } | {
5290
+ kind: "run_completed";
5291
+ v: 1;
5292
+ sessionId: string;
5293
+ eventIndex: number;
5294
+ eventId: string;
5295
+ dedupeKey: string;
5296
+ scope: {
5297
+ runId: string;
5298
+ };
5299
+ data: {
5300
+ startGitSha: string | null;
5301
+ endGitSha: string | null;
5302
+ gitBranch: string | null;
5303
+ agentCommitShas: string[];
5304
+ captureConfidence: "high" | "none";
5305
+ durationMs?: number | undefined;
5306
+ };
5307
+ timestampMs: number;
5199
5308
  })[];
5200
5309
  manifest: ({
5201
5310
  kind: "segment_closed";
@@ -5790,6 +5899,25 @@ export declare const SessionContentsV1Schema: z.ZodObject<{
5790
5899
  traceId: string;
5791
5900
  };
5792
5901
  timestampMs: number;
5902
+ } | {
5903
+ kind: "run_completed";
5904
+ v: 1;
5905
+ sessionId: string;
5906
+ eventIndex: number;
5907
+ eventId: string;
5908
+ dedupeKey: string;
5909
+ scope: {
5910
+ runId: string;
5911
+ };
5912
+ data: {
5913
+ startGitSha: string | null;
5914
+ endGitSha: string | null;
5915
+ gitBranch: string | null;
5916
+ agentCommitShas: string[];
5917
+ captureConfidence: "high" | "none";
5918
+ durationMs?: number | undefined;
5919
+ };
5920
+ timestampMs: number;
5793
5921
  })[];
5794
5922
  manifest: ({
5795
5923
  kind: "segment_closed";
@@ -8274,6 +8402,96 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
8274
8402
  traceId: string;
8275
8403
  };
8276
8404
  timestampMs: number;
8405
+ }>, z.ZodObject<{
8406
+ v: z.ZodLiteral<1>;
8407
+ eventId: z.ZodString;
8408
+ eventIndex: z.ZodNumber;
8409
+ sessionId: z.ZodString;
8410
+ dedupeKey: z.ZodString;
8411
+ timestampMs: z.ZodNumber;
8412
+ } & {
8413
+ kind: z.ZodLiteral<"run_completed">;
8414
+ scope: z.ZodObject<{
8415
+ runId: z.ZodString;
8416
+ }, "strip", z.ZodTypeAny, {
8417
+ runId: string;
8418
+ }, {
8419
+ runId: string;
8420
+ }>;
8421
+ data: z.ZodEffects<z.ZodObject<{
8422
+ startGitSha: z.ZodNullable<z.ZodString>;
8423
+ endGitSha: z.ZodNullable<z.ZodString>;
8424
+ gitBranch: z.ZodNullable<z.ZodString>;
8425
+ agentCommitShas: z.ZodArray<z.ZodString, "many">;
8426
+ captureConfidence: z.ZodEnum<["high", "none"]>;
8427
+ durationMs: z.ZodOptional<z.ZodNumber>;
8428
+ }, "strip", z.ZodTypeAny, {
8429
+ startGitSha: string | null;
8430
+ endGitSha: string | null;
8431
+ gitBranch: string | null;
8432
+ agentCommitShas: string[];
8433
+ captureConfidence: "high" | "none";
8434
+ durationMs?: number | undefined;
8435
+ }, {
8436
+ startGitSha: string | null;
8437
+ endGitSha: string | null;
8438
+ gitBranch: string | null;
8439
+ agentCommitShas: string[];
8440
+ captureConfidence: "high" | "none";
8441
+ durationMs?: number | undefined;
8442
+ }>, {
8443
+ startGitSha: string | null;
8444
+ endGitSha: string | null;
8445
+ gitBranch: string | null;
8446
+ agentCommitShas: string[];
8447
+ captureConfidence: "high" | "none";
8448
+ durationMs?: number | undefined;
8449
+ }, {
8450
+ startGitSha: string | null;
8451
+ endGitSha: string | null;
8452
+ gitBranch: string | null;
8453
+ agentCommitShas: string[];
8454
+ captureConfidence: "high" | "none";
8455
+ durationMs?: number | undefined;
8456
+ }>;
8457
+ }, "strip", z.ZodTypeAny, {
8458
+ kind: "run_completed";
8459
+ v: 1;
8460
+ sessionId: string;
8461
+ eventIndex: number;
8462
+ eventId: string;
8463
+ dedupeKey: string;
8464
+ scope: {
8465
+ runId: string;
8466
+ };
8467
+ data: {
8468
+ startGitSha: string | null;
8469
+ endGitSha: string | null;
8470
+ gitBranch: string | null;
8471
+ agentCommitShas: string[];
8472
+ captureConfidence: "high" | "none";
8473
+ durationMs?: number | undefined;
8474
+ };
8475
+ timestampMs: number;
8476
+ }, {
8477
+ kind: "run_completed";
8478
+ v: 1;
8479
+ sessionId: string;
8480
+ eventIndex: number;
8481
+ eventId: string;
8482
+ dedupeKey: string;
8483
+ scope: {
8484
+ runId: string;
8485
+ };
8486
+ data: {
8487
+ startGitSha: string | null;
8488
+ endGitSha: string | null;
8489
+ gitBranch: string | null;
8490
+ agentCommitShas: string[];
8491
+ captureConfidence: "high" | "none";
8492
+ durationMs?: number | undefined;
8493
+ };
8494
+ timestampMs: number;
8277
8495
  }>]>, "many">;
8278
8496
  manifest: z.ZodArray<z.ZodDiscriminatedUnion<"kind", [z.ZodObject<{
8279
8497
  v: z.ZodLiteral<1>;
@@ -10998,6 +11216,25 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
10998
11216
  traceId: string;
10999
11217
  };
11000
11218
  timestampMs: number;
11219
+ } | {
11220
+ kind: "run_completed";
11221
+ v: 1;
11222
+ sessionId: string;
11223
+ eventIndex: number;
11224
+ eventId: string;
11225
+ dedupeKey: string;
11226
+ scope: {
11227
+ runId: string;
11228
+ };
11229
+ data: {
11230
+ startGitSha: string | null;
11231
+ endGitSha: string | null;
11232
+ gitBranch: string | null;
11233
+ agentCommitShas: string[];
11234
+ captureConfidence: "high" | "none";
11235
+ durationMs?: number | undefined;
11236
+ };
11237
+ timestampMs: number;
11001
11238
  })[];
11002
11239
  manifest: ({
11003
11240
  kind: "segment_closed";
@@ -11592,6 +11829,25 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
11592
11829
  traceId: string;
11593
11830
  };
11594
11831
  timestampMs: number;
11832
+ } | {
11833
+ kind: "run_completed";
11834
+ v: 1;
11835
+ sessionId: string;
11836
+ eventIndex: number;
11837
+ eventId: string;
11838
+ dedupeKey: string;
11839
+ scope: {
11840
+ runId: string;
11841
+ };
11842
+ data: {
11843
+ startGitSha: string | null;
11844
+ endGitSha: string | null;
11845
+ gitBranch: string | null;
11846
+ agentCommitShas: string[];
11847
+ captureConfidence: "high" | "none";
11848
+ durationMs?: number | undefined;
11849
+ };
11850
+ timestampMs: number;
11595
11851
  })[];
11596
11852
  manifest: ({
11597
11853
  kind: "segment_closed";
@@ -12215,6 +12471,25 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
12215
12471
  traceId: string;
12216
12472
  };
12217
12473
  timestampMs: number;
12474
+ } | {
12475
+ kind: "run_completed";
12476
+ v: 1;
12477
+ sessionId: string;
12478
+ eventIndex: number;
12479
+ eventId: string;
12480
+ dedupeKey: string;
12481
+ scope: {
12482
+ runId: string;
12483
+ };
12484
+ data: {
12485
+ startGitSha: string | null;
12486
+ endGitSha: string | null;
12487
+ gitBranch: string | null;
12488
+ agentCommitShas: string[];
12489
+ captureConfidence: "high" | "none";
12490
+ durationMs?: number | undefined;
12491
+ };
12492
+ timestampMs: number;
12218
12493
  })[];
12219
12494
  manifest: ({
12220
12495
  kind: "segment_closed";
@@ -12826,6 +13101,25 @@ export declare const ExportBundleV1Schema: z.ZodObject<{
12826
13101
  traceId: string;
12827
13102
  };
12828
13103
  timestampMs: number;
13104
+ } | {
13105
+ kind: "run_completed";
13106
+ v: 1;
13107
+ sessionId: string;
13108
+ eventIndex: number;
13109
+ eventId: string;
13110
+ dedupeKey: string;
13111
+ scope: {
13112
+ runId: string;
13113
+ };
13114
+ data: {
13115
+ startGitSha: string | null;
13116
+ endGitSha: string | null;
13117
+ gitBranch: string | null;
13118
+ agentCommitShas: string[];
13119
+ captureConfidence: "high" | "none";
13120
+ durationMs?: number | undefined;
13121
+ };
13122
+ timestampMs: number;
12829
13123
  })[];
12830
13124
  manifest: ({
12831
13125
  kind: "segment_closed";
@@ -2460,5 +2460,95 @@ export declare const DomainEventV1Schema: z.ZodDiscriminatedUnion<"kind", [z.Zod
2460
2460
  traceId: string;
2461
2461
  };
2462
2462
  timestampMs: number;
2463
+ }>, z.ZodObject<{
2464
+ v: z.ZodLiteral<1>;
2465
+ eventId: z.ZodString;
2466
+ eventIndex: z.ZodNumber;
2467
+ sessionId: z.ZodString;
2468
+ dedupeKey: z.ZodString;
2469
+ timestampMs: z.ZodNumber;
2470
+ } & {
2471
+ kind: z.ZodLiteral<"run_completed">;
2472
+ scope: z.ZodObject<{
2473
+ runId: z.ZodString;
2474
+ }, "strip", z.ZodTypeAny, {
2475
+ runId: string;
2476
+ }, {
2477
+ runId: string;
2478
+ }>;
2479
+ data: z.ZodEffects<z.ZodObject<{
2480
+ startGitSha: z.ZodNullable<z.ZodString>;
2481
+ endGitSha: z.ZodNullable<z.ZodString>;
2482
+ gitBranch: z.ZodNullable<z.ZodString>;
2483
+ agentCommitShas: z.ZodArray<z.ZodString, "many">;
2484
+ captureConfidence: z.ZodEnum<["high", "none"]>;
2485
+ durationMs: z.ZodOptional<z.ZodNumber>;
2486
+ }, "strip", z.ZodTypeAny, {
2487
+ startGitSha: string | null;
2488
+ endGitSha: string | null;
2489
+ gitBranch: string | null;
2490
+ agentCommitShas: string[];
2491
+ captureConfidence: "high" | "none";
2492
+ durationMs?: number | undefined;
2493
+ }, {
2494
+ startGitSha: string | null;
2495
+ endGitSha: string | null;
2496
+ gitBranch: string | null;
2497
+ agentCommitShas: string[];
2498
+ captureConfidence: "high" | "none";
2499
+ durationMs?: number | undefined;
2500
+ }>, {
2501
+ startGitSha: string | null;
2502
+ endGitSha: string | null;
2503
+ gitBranch: string | null;
2504
+ agentCommitShas: string[];
2505
+ captureConfidence: "high" | "none";
2506
+ durationMs?: number | undefined;
2507
+ }, {
2508
+ startGitSha: string | null;
2509
+ endGitSha: string | null;
2510
+ gitBranch: string | null;
2511
+ agentCommitShas: string[];
2512
+ captureConfidence: "high" | "none";
2513
+ durationMs?: number | undefined;
2514
+ }>;
2515
+ }, "strip", z.ZodTypeAny, {
2516
+ kind: "run_completed";
2517
+ v: 1;
2518
+ sessionId: string;
2519
+ eventIndex: number;
2520
+ eventId: string;
2521
+ dedupeKey: string;
2522
+ scope: {
2523
+ runId: string;
2524
+ };
2525
+ data: {
2526
+ startGitSha: string | null;
2527
+ endGitSha: string | null;
2528
+ gitBranch: string | null;
2529
+ agentCommitShas: string[];
2530
+ captureConfidence: "high" | "none";
2531
+ durationMs?: number | undefined;
2532
+ };
2533
+ timestampMs: number;
2534
+ }, {
2535
+ kind: "run_completed";
2536
+ v: 1;
2537
+ sessionId: string;
2538
+ eventIndex: number;
2539
+ eventId: string;
2540
+ dedupeKey: string;
2541
+ scope: {
2542
+ runId: string;
2543
+ };
2544
+ data: {
2545
+ startGitSha: string | null;
2546
+ endGitSha: string | null;
2547
+ gitBranch: string | null;
2548
+ agentCommitShas: string[];
2549
+ captureConfidence: "high" | "none";
2550
+ durationMs?: number | undefined;
2551
+ };
2552
+ timestampMs: number;
2463
2553
  }>]>;
2464
2554
  export type DomainEventV1 = z.infer<typeof DomainEventV1Schema>;
@@ -257,4 +257,20 @@ exports.DomainEventV1Schema = zod_1.z.discriminatedUnion('kind', [
257
257
  return totalBytes <= constants_js_1.MAX_DECISION_TRACE_TOTAL_BYTES;
258
258
  }, { message: `Decision trace total bytes exceeds ${constants_js_1.MAX_DECISION_TRACE_TOTAL_BYTES}` }),
259
259
  }),
260
+ exports.DomainEventEnvelopeV1Schema.extend({
261
+ kind: zod_1.z.literal('run_completed'),
262
+ scope: zod_1.z.object({ runId: zod_1.z.string().min(1) }),
263
+ data: zod_1.z.object({
264
+ startGitSha: zod_1.z.string().nullable(),
265
+ endGitSha: zod_1.z.string().nullable(),
266
+ gitBranch: zod_1.z.string().nullable(),
267
+ agentCommitShas: zod_1.z.array(zod_1.z.string()),
268
+ captureConfidence: zod_1.z.enum(['high', 'none']),
269
+ durationMs: zod_1.z.number().optional(),
270
+ }).superRefine((d, ctx) => {
271
+ if (d.captureConfidence === 'high' && d.agentCommitShas.length === 0) {
272
+ ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, message: "captureConfidence 'high' requires at least one agentCommitSha" });
273
+ }
274
+ }),
275
+ }),
260
276
  ]);
@@ -0,0 +1,15 @@
1
+ import type { DomainEventV1 } from '../durable-core/schemas/session/index.js';
2
+ export interface SessionMetricsV2 {
3
+ readonly startGitSha: string | null;
4
+ readonly endGitSha: string | null;
5
+ readonly gitBranch: string | null;
6
+ readonly agentCommitShas: readonly string[];
7
+ readonly captureConfidence: 'high' | 'medium' | 'none';
8
+ readonly durationMs: number | undefined;
9
+ readonly outcome: 'success' | 'partial' | 'abandoned' | 'error' | null;
10
+ readonly prNumbers: readonly number[];
11
+ readonly filesChanged: number | null;
12
+ readonly linesAdded: number | null;
13
+ readonly linesRemoved: number | null;
14
+ }
15
+ export declare function projectSessionMetricsV2(events: readonly DomainEventV1[]): SessionMetricsV2 | null;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectSessionMetricsV2 = projectSessionMetricsV2;
4
+ const constants_js_1 = require("../durable-core/constants.js");
5
+ function projectSessionMetricsV2(events) {
6
+ let runCompletedData = null;
7
+ let runCompletedRunId = null;
8
+ for (const e of events) {
9
+ const asUnknown = e;
10
+ if (asUnknown.kind === 'run_completed') {
11
+ runCompletedData = asUnknown.data;
12
+ runCompletedRunId = asUnknown.scope?.runId ?? null;
13
+ break;
14
+ }
15
+ }
16
+ if (runCompletedData === null) {
17
+ return null;
18
+ }
19
+ const metricsContext = {};
20
+ for (const e of events) {
21
+ if (e.kind !== constants_js_1.EVENT_KIND.CONTEXT_SET)
22
+ continue;
23
+ if (runCompletedRunId !== null && e.scope?.runId !== runCompletedRunId)
24
+ continue;
25
+ const ctx = e.data.context;
26
+ if (!ctx || typeof ctx !== 'object' || Array.isArray(ctx))
27
+ continue;
28
+ const ctxObj = ctx;
29
+ for (const [key, value] of Object.entries(ctxObj)) {
30
+ if (key.startsWith('metrics_')) {
31
+ metricsContext[key] = value;
32
+ }
33
+ }
34
+ }
35
+ const d = runCompletedData;
36
+ const startGitSha = typeof d.startGitSha === 'string' ? d.startGitSha : null;
37
+ const endGitSha = typeof d.endGitSha === 'string' ? d.endGitSha : null;
38
+ const gitBranch = typeof d.gitBranch === 'string' ? d.gitBranch : null;
39
+ const agentCommitShas = [];
40
+ if (Array.isArray(d.agentCommitShas)) {
41
+ for (const sha of d.agentCommitShas) {
42
+ if (typeof sha === 'string') {
43
+ agentCommitShas.push(sha);
44
+ }
45
+ }
46
+ }
47
+ const captureConfidenceRaw = d.captureConfidence;
48
+ const captureConfidence = captureConfidenceRaw === 'high' || captureConfidenceRaw === 'medium' || captureConfidenceRaw === 'none'
49
+ ? captureConfidenceRaw
50
+ : 'none';
51
+ const durationMs = typeof d.durationMs === 'number' && Number.isFinite(d.durationMs)
52
+ ? d.durationMs
53
+ : undefined;
54
+ const outcomeRaw = metricsContext['metrics_outcome'];
55
+ const outcome = outcomeRaw === 'success' || outcomeRaw === 'partial' || outcomeRaw === 'abandoned' || outcomeRaw === 'error'
56
+ ? outcomeRaw
57
+ : null;
58
+ const prNumbers = [];
59
+ const prNumbersRaw = metricsContext['metrics_pr_numbers'];
60
+ if (Array.isArray(prNumbersRaw)) {
61
+ for (const n of prNumbersRaw) {
62
+ if (typeof n === 'number' && Number.isFinite(n)) {
63
+ prNumbers.push(n);
64
+ }
65
+ }
66
+ }
67
+ const commitShasRaw = metricsContext['metrics_commit_shas'];
68
+ const metricCommitShas = [];
69
+ if (Array.isArray(commitShasRaw)) {
70
+ for (const sha of commitShasRaw) {
71
+ if (typeof sha === 'string') {
72
+ metricCommitShas.push(sha);
73
+ }
74
+ }
75
+ }
76
+ const finalAgentCommitShas = metricCommitShas.length > 0 ? metricCommitShas : agentCommitShas;
77
+ const filesChangedRaw = metricsContext['metrics_files_changed'];
78
+ const filesChanged = typeof filesChangedRaw === 'number' && Number.isFinite(filesChangedRaw)
79
+ ? filesChangedRaw
80
+ : null;
81
+ const linesAddedRaw = metricsContext['metrics_lines_added'];
82
+ const linesAdded = typeof linesAddedRaw === 'number' && Number.isFinite(linesAddedRaw)
83
+ ? linesAddedRaw
84
+ : null;
85
+ const linesRemovedRaw = metricsContext['metrics_lines_removed'];
86
+ const linesRemoved = typeof linesRemovedRaw === 'number' && Number.isFinite(linesRemovedRaw)
87
+ ? linesRemovedRaw
88
+ : null;
89
+ return {
90
+ startGitSha,
91
+ endGitSha,
92
+ gitBranch,
93
+ agentCommitShas: finalAgentCommitShas,
94
+ captureConfidence,
95
+ durationMs,
96
+ outcome,
97
+ prNumbers,
98
+ filesChanged,
99
+ linesAdded,
100
+ linesRemoved,
101
+ };
102
+ }
@@ -41,6 +41,8 @@ const express_1 = __importDefault(require("express"));
41
41
  const path_1 = __importDefault(require("path"));
42
42
  const fs_1 = __importDefault(require("fs"));
43
43
  const os_1 = __importDefault(require("os"));
44
+ const child_process_1 = require("child_process");
45
+ const util_1 = require("util");
44
46
  const worktree_service_js_1 = require("./worktree-service.js");
45
47
  const workflow_js_1 = require("../../types/workflow.js");
46
48
  const dev_mode_js_1 = require("../../mcp/dev-mode.js");
@@ -467,6 +469,63 @@ function mountConsoleRoutes(app, consoleService, workflowService, timingRingBuff
467
469
  res.status(status).json({ success: false, error: error.message });
468
470
  });
469
471
  });
472
+ const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
473
+ const DIFF_GIT_TIMEOUT_MS = 10000;
474
+ function isDiffExecError(e) {
475
+ if (!(e instanceof Error))
476
+ return false;
477
+ if ('killed' in e)
478
+ return true;
479
+ const sys = e.syscall ?? '';
480
+ return sys.startsWith('spawn');
481
+ }
482
+ app.get('/api/v2/sessions/:sessionId/diff-summary', async (req, res) => {
483
+ const { sessionId } = req.params;
484
+ const sessionResult = await consoleService.getSessionDetail(sessionId);
485
+ if (sessionResult.isErr()) {
486
+ const status = sessionResult.error.code === 'SESSION_LOAD_FAILED' ? 404 : 500;
487
+ res.status(status).json({ success: false, error: sessionResult.error.message });
488
+ return;
489
+ }
490
+ const sessionDetail = sessionResult.value;
491
+ const metrics = sessionDetail.metrics;
492
+ if (!metrics) {
493
+ res.status(422).json({ success: false, error: 'No metrics available for this session' });
494
+ return;
495
+ }
496
+ const { startGitSha, endGitSha } = metrics;
497
+ if (!startGitSha || !endGitSha) {
498
+ res.status(422).json({ success: false, error: 'Git SHAs not available in session metrics' });
499
+ return;
500
+ }
501
+ const repoRoot = sessionDetail.repoRoot;
502
+ if (!repoRoot) {
503
+ res.status(422).json({ success: false, error: 'Repo root not available for this session' });
504
+ return;
505
+ }
506
+ try {
507
+ const { stdout } = await execFileAsync('git', ['diff', `${startGitSha}..${endGitSha}`, '--shortstat'], { cwd: repoRoot, encoding: 'utf-8', timeout: DIFF_GIT_TIMEOUT_MS });
508
+ const match = stdout.trim().match(/(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?/);
509
+ if (!match) {
510
+ res.json({ success: true, data: { linesAdded: 0, linesRemoved: 0, filesChanged: 0 } });
511
+ return;
512
+ }
513
+ const filesChanged = parseInt(match[1] ?? '0', 10);
514
+ const linesAdded = parseInt(match[2] ?? '0', 10);
515
+ const linesRemoved = parseInt(match[3] ?? '0', 10);
516
+ res.json({ success: true, data: { linesAdded, linesRemoved, filesChanged } });
517
+ }
518
+ catch (e) {
519
+ if (isDiffExecError(e)) {
520
+ const errMsg = e instanceof Error && 'killed' in e && e.killed
521
+ ? 'Diff timed out: repository too large or slow'
522
+ : `Diff failed: git unavailable or invalid SHAs`;
523
+ res.status(503).json({ success: false, error: errMsg });
524
+ return;
525
+ }
526
+ throw e;
527
+ }
528
+ });
470
529
  if (workflowService) {
471
530
  app.get('/api/v2/workflows', async (_req, res) => {
472
531
  try {