@aaronshaf/ger 2.0.8 → 2.0.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aaronshaf/ger",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "description": "Gerrit CLI and SDK - A modern CLI tool and TypeScript SDK for Gerrit Code Review, built with Effect-TS",
5
5
  "keywords": [
6
6
  "gerrit",
package/src/cli/index.ts CHANGED
@@ -48,6 +48,43 @@ const program = new Command()
48
48
 
49
49
  program.name('ger').description('LLM-centric Gerrit CLI tool').version(getVersion())
50
50
 
51
+ program.addHelpText(
52
+ 'after',
53
+ `
54
+ CHANGE-ID FORMATS
55
+ Accepts numeric change numbers (12345) or full Change-IDs (I1234abc...).
56
+ Many commands auto-detect from HEAD commit's Change-Id footer when the
57
+ argument is omitted.
58
+
59
+ OUTPUT FORMATS
60
+ --json Structured JSON output for programmatic consumption
61
+ --xml XML with CDATA-wrapped content, optimized for LLM consumption
62
+ (default) Plain text for human reading
63
+ Most commands support both --json and --xml.
64
+
65
+ PIPING / STDIN
66
+ comment Reads message from stdin if no -m flag is provided
67
+ comment --batch Reads a JSON array from stdin for bulk commenting
68
+
69
+ AUTO-DETECTION
70
+ These commands auto-detect the change from HEAD's Change-Id footer when
71
+ the change-id argument is omitted:
72
+ show, build-status, topic, rebase, extract-url, diff, comments, vote
73
+
74
+ COMMON LLM WORKFLOWS
75
+ Review a change: ger show <id> → ger diff <id> → ger comments <id>
76
+ Post a review: ger comment <id> -m "..." → ger vote <id> <label> <score>
77
+ Manage changes: ger push, ger checkout <id>, ger abandon <id>, ger submit <id>
78
+ Check CI: ger build-status <id> --exit-status
79
+
80
+ EXIT CODES
81
+ build-status --exit-status returns non-zero on build failure (useful for scripting).
82
+
83
+ SUBCOMMAND HELP
84
+ Run ger <command> --help for detailed usage and examples.
85
+ `,
86
+ )
87
+
51
88
  registerCommands(program)
52
89
 
53
90
  program.parse(process.argv)
@@ -19,8 +19,34 @@ export const GerritCredentials: Schema.Schema<{
19
19
  ),
20
20
  })
21
21
  export type GerritCredentials = Schema.Schema.Type<typeof GerritCredentials>
22
+ export const FileInfo: Schema.Schema<{
23
+ readonly status?: 'A' | 'D' | 'R' | 'C' | 'M'
24
+ readonly lines_inserted?: number
25
+ readonly lines_deleted?: number
26
+ readonly size?: number
27
+ readonly size_delta?: number
28
+ readonly old_path?: string
29
+ readonly binary?: boolean
30
+ }> = Schema.Struct({
31
+ status: Schema.optional(Schema.Literal('A', 'D', 'R', 'C', 'M')), // Added, Deleted, Renamed, Copied, Modified
32
+ lines_inserted: Schema.optional(Schema.Number),
33
+ lines_deleted: Schema.optional(Schema.Number),
34
+ size_delta: Schema.optional(Schema.Number),
35
+ size: Schema.optional(Schema.Number),
36
+ old_path: Schema.optional(Schema.String),
37
+ binary: Schema.optional(Schema.Boolean),
38
+ })
39
+ export type FileInfo = Schema.Schema.Type<typeof FileInfo>
22
40
 
23
- export interface RevisionInfoType {
41
+ type PersonDate = { readonly name: string; readonly email: string; readonly date: string }
42
+ type ChangeMessage = {
43
+ readonly id: string
44
+ readonly message: string
45
+ readonly date: string
46
+ readonly _revision_number?: number
47
+ readonly tag?: string
48
+ }
49
+ type RevisionShape = {
24
50
  readonly kind?: string
25
51
  readonly _number: number
26
52
  readonly created: string
@@ -28,39 +54,21 @@ export interface RevisionInfoType {
28
54
  readonly _account_id: number
29
55
  readonly name?: string
30
56
  readonly email?: string
57
+ readonly username?: string
31
58
  }
32
59
  readonly ref: string
33
60
  readonly fetch?: Record<string, unknown>
61
+ readonly description?: string
34
62
  readonly commit?: {
35
63
  readonly commit: string
36
- readonly parents: ReadonlyArray<{
37
- readonly commit: string
38
- readonly subject: string
39
- }>
40
- readonly author: {
41
- readonly name: string
42
- readonly email: string
43
- readonly date: string
44
- }
45
- readonly committer: {
46
- readonly name: string
47
- readonly email: string
48
- readonly date: string
49
- }
64
+ readonly parents: ReadonlyArray<{ readonly commit: string; readonly subject: string }>
65
+ readonly author: PersonDate
66
+ readonly committer: PersonDate
50
67
  readonly subject: string
51
68
  readonly message: string
52
69
  }
53
- readonly files?: Record<
54
- string,
55
- {
56
- readonly status?: 'A' | 'D' | 'R' | 'C' | 'M'
57
- readonly lines_inserted?: number
58
- readonly lines_deleted?: number
59
- readonly size?: number
60
- readonly size_delta?: number
61
- readonly old_path?: string
62
- }
63
- >
70
+ readonly files?: Record<string, FileInfo>
71
+ readonly actions?: Record<string, unknown>
64
72
  }
65
73
 
66
74
  type ChangeReviewerAccount = {
@@ -68,12 +76,16 @@ type ChangeReviewerAccount = {
68
76
  readonly name?: string
69
77
  readonly email?: string
70
78
  readonly username?: string
79
+ readonly display_name?: string
80
+ readonly tags?: ReadonlyArray<string>
71
81
  }
72
82
  const ChangeReviewerAccountInfo: Schema.Schema<ChangeReviewerAccount> = Schema.Struct({
73
83
  _account_id: Schema.optional(Schema.Number),
74
84
  name: Schema.optional(Schema.String),
75
85
  email: Schema.optional(Schema.String),
76
86
  username: Schema.optional(Schema.String),
87
+ display_name: Schema.optional(Schema.String),
88
+ tags: Schema.optional(Schema.Array(Schema.String)),
77
89
  })
78
90
  type ChangeReviewerMap = Partial<
79
91
  Record<'REVIEWER' | 'CC' | 'REMOVED', ReadonlyArray<ChangeReviewerAccount>>
@@ -84,11 +96,19 @@ export const AccountInfo: Schema.Schema<{
84
96
  readonly name?: string
85
97
  readonly email?: string
86
98
  readonly username?: string
99
+ readonly display_name?: string
100
+ readonly tags?: ReadonlyArray<string>
101
+ readonly inactive?: boolean
102
+ readonly status?: string
87
103
  }> = Schema.Struct({
88
104
  _account_id: Schema.Number,
89
105
  name: Schema.optional(Schema.String),
90
106
  email: Schema.optional(Schema.String),
91
107
  username: Schema.optional(Schema.String),
108
+ display_name: Schema.optional(Schema.String),
109
+ tags: Schema.optional(Schema.Array(Schema.String)),
110
+ inactive: Schema.optional(Schema.Boolean),
111
+ status: Schema.optional(Schema.String),
92
112
  })
93
113
  export type AccountInfo = Schema.Schema.Type<typeof AccountInfo>
94
114
 
@@ -101,51 +121,35 @@ export const ChangeInfo: Schema.Schema<{
101
121
  readonly status: 'NEW' | 'MERGED' | 'ABANDONED' | 'DRAFT'
102
122
  readonly created?: string
103
123
  readonly updated?: string
124
+ readonly submitted?: string
104
125
  readonly insertions?: number
105
126
  readonly deletions?: number
106
127
  readonly _number: number
107
- readonly owner?: {
108
- readonly _account_id: number
109
- readonly name?: string
110
- readonly email?: string
111
- readonly username?: string
112
- }
128
+ readonly owner?: AccountInfo
113
129
  readonly labels?: Record<
114
130
  string,
115
131
  {
116
- readonly approved?: {
117
- readonly _account_id: number
118
- readonly name?: string
119
- readonly email?: string
120
- readonly username?: string
121
- }
122
- readonly rejected?: {
123
- readonly _account_id: number
124
- readonly name?: string
125
- readonly email?: string
126
- readonly username?: string
127
- }
128
- readonly recommended?: {
129
- readonly _account_id: number
130
- readonly name?: string
131
- readonly email?: string
132
- readonly username?: string
133
- }
134
- readonly disliked?: {
135
- readonly _account_id: number
136
- readonly name?: string
137
- readonly email?: string
138
- readonly username?: string
139
- }
132
+ readonly approved?: AccountInfo
133
+ readonly rejected?: AccountInfo
134
+ readonly recommended?: AccountInfo
135
+ readonly disliked?: AccountInfo
140
136
  readonly value?: number
141
137
  }
142
138
  >
143
139
  readonly submittable?: boolean
144
140
  readonly work_in_progress?: boolean
141
+ readonly is_private?: boolean
145
142
  readonly current_revision?: string
146
- readonly revisions?: Record<string, RevisionInfoType>
143
+ readonly revisions?: Record<string, RevisionShape>
147
144
  readonly topic?: string
145
+ readonly hashtags?: ReadonlyArray<string>
148
146
  readonly reviewers?: ChangeReviewerMap
147
+ readonly mergeable?: boolean
148
+ readonly unresolved_comment_count?: number
149
+ readonly total_comment_count?: number
150
+ readonly attention_set?: Record<string, unknown>
151
+ readonly submit_type?: string
152
+ readonly messages?: ReadonlyArray<ChangeMessage>
149
153
  }> = Schema.Struct({
150
154
  id: Schema.String,
151
155
  project: Schema.String,
@@ -155,6 +159,7 @@ export const ChangeInfo: Schema.Schema<{
155
159
  status: Schema.Literal('NEW', 'MERGED', 'ABANDONED', 'DRAFT'),
156
160
  created: Schema.optional(Schema.String),
157
161
  updated: Schema.optional(Schema.String),
162
+ submitted: Schema.optional(Schema.String),
158
163
  insertions: Schema.optional(Schema.Number),
159
164
  deletions: Schema.optional(Schema.Number),
160
165
  _number: Schema.Number,
@@ -171,6 +176,7 @@ export const ChangeInfo: Schema.Schema<{
171
176
  default_value: Schema.optional(Schema.Number),
172
177
  blocking: Schema.optional(Schema.Boolean),
173
178
  optional: Schema.optional(Schema.Boolean),
179
+ description: Schema.optional(Schema.String),
174
180
  values: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.String })),
175
181
  all: Schema.optional(
176
182
  Schema.Array(
@@ -180,6 +186,7 @@ export const ChangeInfo: Schema.Schema<{
180
186
  email: Schema.optional(Schema.String),
181
187
  username: Schema.optional(Schema.String),
182
188
  value: Schema.optional(Schema.Number),
189
+ post_submit: Schema.optional(Schema.Boolean),
183
190
  permitted_voting_range: Schema.optional(
184
191
  Schema.Struct({ min: Schema.Number, max: Schema.Number }),
185
192
  ),
@@ -193,9 +200,11 @@ export const ChangeInfo: Schema.Schema<{
193
200
  ),
194
201
  submittable: Schema.optional(Schema.Boolean),
195
202
  work_in_progress: Schema.optional(Schema.Boolean),
203
+ is_private: Schema.optional(Schema.Boolean),
196
204
  current_revision: Schema.optional(Schema.String),
197
205
  revisions: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
198
206
  topic: Schema.optional(Schema.String),
207
+ hashtags: Schema.optional(Schema.Array(Schema.String)),
199
208
  reviewers: Schema.optional(
200
209
  Schema.Struct({
201
210
  REVIEWER: Schema.optional(Schema.Array(ChangeReviewerAccountInfo)),
@@ -203,6 +212,22 @@ export const ChangeInfo: Schema.Schema<{
203
212
  REMOVED: Schema.optional(Schema.Array(ChangeReviewerAccountInfo)),
204
213
  }),
205
214
  ),
215
+ mergeable: Schema.optional(Schema.Boolean),
216
+ unresolved_comment_count: Schema.optional(Schema.Number),
217
+ total_comment_count: Schema.optional(Schema.Number),
218
+ attention_set: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
219
+ submit_type: Schema.optional(Schema.String),
220
+ messages: Schema.optional(
221
+ Schema.Array(
222
+ Schema.Struct({
223
+ id: Schema.String,
224
+ message: Schema.String,
225
+ date: Schema.String,
226
+ _revision_number: Schema.optional(Schema.Number),
227
+ tag: Schema.optional(Schema.String),
228
+ }),
229
+ ),
230
+ ),
206
231
  })
207
232
  export type ChangeInfo = Schema.Schema.Type<typeof ChangeInfo>
208
233
 
@@ -221,6 +246,8 @@ export type CommentInput = Schema.Schema.Type<typeof CommentInput>
221
246
  export const CommentInfo: Schema.Schema<{
222
247
  readonly id: string
223
248
  readonly path?: string
249
+ readonly patch_set?: number
250
+ readonly side?: 'PARENT' | 'REVISION'
224
251
  readonly line?: number
225
252
  readonly range?: {
226
253
  readonly start_line: number
@@ -229,17 +256,18 @@ export const CommentInfo: Schema.Schema<{
229
256
  readonly end_character?: number
230
257
  }
231
258
  readonly message: string
232
- readonly author?: {
233
- readonly name?: string
234
- readonly email?: string
235
- readonly _account_id?: number
236
- }
259
+ readonly author?: ChangeReviewerAccount
237
260
  readonly updated?: string
238
261
  readonly unresolved?: boolean
239
262
  readonly in_reply_to?: string
263
+ readonly tag?: string
264
+ readonly change_message_id?: string
265
+ readonly commit_id?: string
240
266
  }> = Schema.Struct({
241
267
  id: Schema.String,
242
268
  path: Schema.optional(Schema.String),
269
+ patch_set: Schema.optional(Schema.Number),
270
+ side: Schema.optional(Schema.Literal('PARENT', 'REVISION')),
243
271
  line: Schema.optional(Schema.Number),
244
272
  range: Schema.optional(
245
273
  Schema.Struct({
@@ -250,40 +278,29 @@ export const CommentInfo: Schema.Schema<{
250
278
  }),
251
279
  ),
252
280
  message: Schema.String,
253
- author: Schema.optional(
254
- Schema.Struct({
255
- name: Schema.optional(Schema.String),
256
- email: Schema.optional(Schema.String),
257
- _account_id: Schema.optional(Schema.Number),
258
- }),
259
- ),
281
+ author: Schema.optional(ChangeReviewerAccountInfo),
260
282
  updated: Schema.optional(Schema.String),
261
283
  unresolved: Schema.optional(Schema.Boolean),
262
284
  in_reply_to: Schema.optional(Schema.String),
285
+ tag: Schema.optional(Schema.String),
286
+ change_message_id: Schema.optional(Schema.String),
287
+ commit_id: Schema.optional(Schema.String),
263
288
  })
264
289
  export type CommentInfo = Schema.Schema.Type<typeof CommentInfo>
265
290
 
266
291
  export const MessageInfo: Schema.Schema<{
267
292
  readonly id: string
268
293
  readonly message: string
269
- readonly author?: {
270
- readonly _account_id: number
271
- readonly name?: string
272
- readonly email?: string
273
- }
294
+ readonly author?: AccountInfo
295
+ readonly real_author?: AccountInfo
274
296
  readonly date: string
275
297
  readonly _revision_number?: number
276
298
  readonly tag?: string
277
299
  }> = Schema.Struct({
278
300
  id: Schema.String,
279
301
  message: Schema.String,
280
- author: Schema.optional(
281
- Schema.Struct({
282
- _account_id: Schema.Number,
283
- name: Schema.optional(Schema.String),
284
- email: Schema.optional(Schema.String),
285
- }),
286
- ),
302
+ author: Schema.optional(AccountInfo),
303
+ real_author: Schema.optional(AccountInfo),
287
304
  date: Schema.String,
288
305
  _revision_number: Schema.optional(Schema.Number),
289
306
  tag: Schema.optional(Schema.String),
@@ -341,35 +358,35 @@ export const ProjectInfo: Schema.Schema<{
341
358
  readonly id: string
342
359
  readonly name: string
343
360
  readonly parent?: string
361
+ readonly description?: string
344
362
  readonly state?: 'ACTIVE' | 'READ_ONLY' | 'HIDDEN'
345
363
  }> = Schema.Struct({
346
364
  id: Schema.String,
347
365
  name: Schema.String,
348
366
  parent: Schema.optional(Schema.String),
367
+ description: Schema.optional(Schema.String),
349
368
  state: Schema.optional(Schema.Literal('ACTIVE', 'READ_ONLY', 'HIDDEN')),
350
369
  })
351
370
  export type ProjectInfo = Schema.Schema.Type<typeof ProjectInfo>
352
371
 
353
- export const FileInfo: Schema.Schema<{
354
- readonly status?: 'A' | 'D' | 'R' | 'C' | 'M'
355
- readonly lines_inserted?: number
356
- readonly lines_deleted?: number
357
- readonly size?: number
358
- readonly size_delta?: number
359
- readonly old_path?: string
372
+ export const DiffFileMeta: Schema.Schema<{
373
+ readonly name: string
374
+ readonly content_type: string
375
+ readonly lines?: number
360
376
  }> = Schema.Struct({
361
- status: Schema.optional(Schema.Literal('A', 'D', 'R', 'C', 'M')), // Added, Deleted, Renamed, Copied, Modified
362
- lines_inserted: Schema.optional(Schema.Number),
363
- lines_deleted: Schema.optional(Schema.Number),
364
- size_delta: Schema.optional(Schema.Number),
365
- size: Schema.optional(Schema.Number),
366
- old_path: Schema.optional(Schema.String),
377
+ name: Schema.String,
378
+ content_type: Schema.String,
379
+ lines: Schema.optional(Schema.Number),
367
380
  })
368
- export type FileInfo = Schema.Schema.Type<typeof FileInfo>
381
+ export type DiffFileMeta = Schema.Schema.Type<typeof DiffFileMeta>
369
382
 
370
383
  export const FileDiffContent: Schema.Schema<{
371
- readonly a?: string
372
- readonly b?: string
384
+ readonly meta_a?: DiffFileMeta
385
+ readonly meta_b?: DiffFileMeta
386
+ readonly binary?: boolean
387
+ readonly change_type?: 'ADDED' | 'MODIFIED' | 'DELETED' | 'RENAMED' | 'COPIED' | 'REWRITE'
388
+ readonly diff_header?: ReadonlyArray<string>
389
+ readonly intraline_status?: 'OK' | 'TIMEOUT' | 'ERROR'
373
390
  readonly content: ReadonlyArray<{
374
391
  readonly a?: ReadonlyArray<string>
375
392
  readonly b?: ReadonlyArray<string>
@@ -382,11 +399,15 @@ export const FileDiffContent: Schema.Schema<{
382
399
  readonly due_to_rebase?: boolean
383
400
  readonly skip?: number
384
401
  }>
385
- readonly change_type?: 'ADDED' | 'MODIFIED' | 'DELETED' | 'RENAMED' | 'COPIED'
386
- readonly diff_header?: ReadonlyArray<string>
387
402
  }> = Schema.Struct({
388
- a: Schema.optional(Schema.String), // Old file content path
389
- b: Schema.optional(Schema.String), // New file content path
403
+ meta_a: Schema.optional(DiffFileMeta),
404
+ meta_b: Schema.optional(DiffFileMeta),
405
+ binary: Schema.optional(Schema.Boolean),
406
+ change_type: Schema.optional(
407
+ Schema.Literal('ADDED', 'MODIFIED', 'DELETED', 'RENAMED', 'COPIED', 'REWRITE'),
408
+ ),
409
+ diff_header: Schema.optional(Schema.Array(Schema.String)),
410
+ intraline_status: Schema.optional(Schema.Literal('OK', 'TIMEOUT', 'ERROR')),
390
411
  content: Schema.Array(
391
412
  Schema.Struct({
392
413
  a: Schema.optional(Schema.Array(Schema.String)), // Lines from old file
@@ -405,8 +426,6 @@ export const FileDiffContent: Schema.Schema<{
405
426
  skip: Schema.optional(Schema.Number),
406
427
  }),
407
428
  ),
408
- change_type: Schema.optional(Schema.Literal('ADDED', 'MODIFIED', 'DELETED', 'RENAMED', 'COPIED')),
409
- diff_header: Schema.optional(Schema.Array(Schema.String)),
410
429
  })
411
430
  export type FileDiffContent = Schema.Schema.Type<typeof FileDiffContent>
412
431
 
@@ -418,25 +437,16 @@ export const RevisionInfo: Schema.Schema<{
418
437
  readonly _account_id: number
419
438
  readonly name?: string
420
439
  readonly email?: string
440
+ readonly username?: string
421
441
  }
422
442
  readonly ref: string
423
443
  readonly fetch?: Record<string, unknown>
444
+ readonly description?: string
424
445
  readonly commit?: {
425
446
  readonly commit: string
426
- readonly parents: ReadonlyArray<{
427
- readonly commit: string
428
- readonly subject: string
429
- }>
430
- readonly author: {
431
- readonly name: string
432
- readonly email: string
433
- readonly date: string
434
- }
435
- readonly committer: {
436
- readonly name: string
437
- readonly email: string
438
- readonly date: string
439
- }
447
+ readonly parents: ReadonlyArray<{ readonly commit: string; readonly subject: string }>
448
+ readonly author: PersonDate
449
+ readonly committer: PersonDate
440
450
  readonly subject: string
441
451
  readonly message: string
442
452
  }
@@ -449,8 +459,10 @@ export const RevisionInfo: Schema.Schema<{
449
459
  readonly size?: number
450
460
  readonly size_delta?: number
451
461
  readonly old_path?: string
462
+ readonly binary?: boolean
452
463
  }
453
464
  >
465
+ readonly actions?: Record<string, unknown>
454
466
  }> = Schema.Struct({
455
467
  kind: Schema.optional(Schema.String),
456
468
  _number: Schema.Number,
@@ -459,9 +471,11 @@ export const RevisionInfo: Schema.Schema<{
459
471
  _account_id: Schema.Number,
460
472
  name: Schema.optional(Schema.String),
461
473
  email: Schema.optional(Schema.String),
474
+ username: Schema.optional(Schema.String),
462
475
  }),
463
476
  ref: Schema.String,
464
477
  fetch: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
478
+ description: Schema.optional(Schema.String),
465
479
  commit: Schema.optional(
466
480
  Schema.Struct({
467
481
  commit: Schema.String,
@@ -486,8 +500,11 @@ export const RevisionInfo: Schema.Schema<{
486
500
  }),
487
501
  ),
488
502
  files: Schema.optional(Schema.Record({ key: Schema.String, value: FileInfo })),
503
+ actions: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.Any })),
489
504
  })
490
505
  export type RevisionInfo = Schema.Schema.Type<typeof RevisionInfo>
506
+ // Backwards-compatible alias used by mock-generator and other consumers
507
+ export type RevisionInfoType = RevisionShape
491
508
 
492
509
  // Diff output format options
493
510
  export const DiffFormat: Schema.Schema<'unified' | 'json' | 'files'> = Schema.Literal(
@@ -550,6 +567,7 @@ const ReviewerAccountInfo = Schema.Struct({
550
567
  _account_id: Schema.Number,
551
568
  name: Schema.optional(Schema.String),
552
569
  email: Schema.optional(Schema.String),
570
+ username: Schema.optional(Schema.String),
553
571
  })
554
572
 
555
573
  export const ReviewerResult: Schema.Schema<{
@@ -558,11 +576,13 @@ export const ReviewerResult: Schema.Schema<{
558
576
  readonly _account_id: number
559
577
  readonly name?: string
560
578
  readonly email?: string
579
+ readonly username?: string
561
580
  }>
562
581
  readonly ccs?: ReadonlyArray<{
563
582
  readonly _account_id: number
564
583
  readonly name?: string
565
584
  readonly email?: string
585
+ readonly username?: string
566
586
  }>
567
587
  readonly error?: string
568
588
  readonly confirm?: boolean
@@ -645,12 +665,7 @@ export const GroupDetailInfo: Schema.Schema<{
645
665
  readonly owner?: string
646
666
  readonly owner_id?: string
647
667
  readonly created_on?: string
648
- readonly members?: ReadonlyArray<{
649
- readonly _account_id: number
650
- readonly name?: string
651
- readonly email?: string
652
- readonly username?: string
653
- }>
668
+ readonly members?: ReadonlyArray<AccountInfo>
654
669
  readonly includes?: ReadonlyArray<{
655
670
  readonly id: string
656
671
  readonly name?: string
@@ -76,9 +76,11 @@ describe('diff command', () => {
76
76
  const mockDiff = {
77
77
  meta_a: {
78
78
  name: 'src/utils.js',
79
+ content_type: 'text/plain',
79
80
  },
80
81
  meta_b: {
81
82
  name: 'src/utils.js',
83
+ content_type: 'text/plain',
82
84
  },
83
85
  content: [
84
86
  {
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
2
  import { Schema } from '@effect/schema'
3
- import { CommentInput, GerritCredentials } from '@/schemas/gerrit'
3
+ import { CommentInput, FileDiffContent, GerritCredentials } from '@/schemas/gerrit'
4
4
 
5
5
  describe('Gerrit Schemas', () => {
6
6
  describe('GerritCredentials', () => {
@@ -82,4 +82,55 @@ describe('Gerrit Schemas', () => {
82
82
  }).toThrow()
83
83
  })
84
84
  })
85
+
86
+ describe('FileDiffContent', () => {
87
+ const baseContent = { content: [] }
88
+
89
+ test('should accept change_type REWRITE', () => {
90
+ const result = Schema.decodeUnknownSync(FileDiffContent)({
91
+ ...baseContent,
92
+ change_type: 'REWRITE',
93
+ })
94
+ expect(result.change_type).toBe('REWRITE')
95
+ })
96
+
97
+ test('should accept intraline_status ERROR', () => {
98
+ const result = Schema.decodeUnknownSync(FileDiffContent)({
99
+ ...baseContent,
100
+ intraline_status: 'ERROR',
101
+ })
102
+ expect(result.intraline_status).toBe('ERROR')
103
+ })
104
+
105
+ test('should accept all valid change_type values', () => {
106
+ const values = ['ADDED', 'MODIFIED', 'DELETED', 'RENAMED', 'COPIED', 'REWRITE'] as const
107
+ for (const change_type of values) {
108
+ const result = Schema.decodeUnknownSync(FileDiffContent)({ ...baseContent, change_type })
109
+ expect(result.change_type).toBe(change_type)
110
+ }
111
+ })
112
+
113
+ test('should accept all valid intraline_status values', () => {
114
+ const values = ['OK', 'TIMEOUT', 'ERROR'] as const
115
+ for (const intraline_status of values) {
116
+ const result = Schema.decodeUnknownSync(FileDiffContent)({
117
+ ...baseContent,
118
+ intraline_status,
119
+ })
120
+ expect(result.intraline_status).toBe(intraline_status)
121
+ }
122
+ })
123
+
124
+ test('should reject invalid change_type', () => {
125
+ expect(() => {
126
+ Schema.decodeUnknownSync(FileDiffContent)({ ...baseContent, change_type: 'FAILURE' })
127
+ }).toThrow()
128
+ })
129
+
130
+ test('should reject invalid intraline_status', () => {
131
+ expect(() => {
132
+ Schema.decodeUnknownSync(FileDiffContent)({ ...baseContent, intraline_status: 'FAILURE' })
133
+ }).toThrow()
134
+ })
135
+ })
85
136
  })