@remogram/provider-gitea-api 0.1.0-beta.2 → 0.1.0-beta.4

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.
Files changed (2) hide show
  1. package/index.js +416 -37
  2. package/package.json +2 -2
package/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  fetchJson,
3
+ fetchJsonWithMeta,
3
4
  sanitizeField,
4
5
  sanitizeUrl,
5
6
  assertGitRef,
@@ -7,23 +8,57 @@ import {
7
8
  gitRevParse,
8
9
  gitCurrentBranch,
9
10
  gitAheadBehind,
11
+ refsInventory,
12
+ crInventory,
13
+ buildMergePlanBodyFromFacts,
14
+ buildChangeRequestOpenedBody,
10
15
  ERROR_CODES,
11
16
  forgeError,
12
17
  forgeIngestCapabilityFacts,
18
+ checkPaginationCapabilityFacts,
19
+ idempotencyScanCapabilityFacts,
20
+ openPullListCapabilityFacts,
21
+ DEFAULT_CHECK_STATUS_PAGE_SIZE,
22
+ MAX_CHECK_STATUS_PAGES,
23
+ DEFAULT_OPEN_PULL_LIST_PAGE_SIZE,
24
+ MAX_OPEN_PULL_IDEMPOTENCY_PAGES,
25
+ paginateCheckStatusPages,
26
+ paginateOffsetListPages,
27
+ fetchWithIngestPageBackoff,
28
+ fetchPageWithIngestBackoff,
29
+ withPerPageParam,
13
30
  apiProviderCommands,
31
+ normalizeCrInventorySort,
32
+ DEFAULT_CR_INVENTORY_SLICE_SORT,
33
+ parseTotalCountHeader,
34
+ isCrInventoryFastPathEligible,
35
+ validateFastPathPageLength,
36
+ isNumberSortFastPathEligible,
37
+ isRecentCreatedFastPathEligible,
38
+ giteaRecentCreatedTailPage,
39
+ isNumberSortFullCollectRequired,
40
+ resolveListTruncatedWithTrustedTotal,
41
+ prepareGiteaOpenPullPageItems,
42
+ orderOpenPullNumbers,
43
+ buildOpenPullListMeta,
44
+ giteaOpenPullSortQuery,
45
+ appendSortQuery,
14
46
  } from '@remogram/core';
15
47
  const PUBLIC_GITEA_HOST = 'gitea.com';
16
48
  const PUBLIC_GITEA_API = 'https://gitea.com/api/v1';
17
49
  const AUTH_CAPABILITIES = [
18
50
  'repo_status',
19
51
  'ref_compare',
52
+ 'ref_inventory',
53
+ 'cr_inventory',
20
54
  'pr_status',
21
55
  'pr_checks',
22
56
  'merge_plan',
23
57
  'sync_plan',
58
+ 'cr_open',
24
59
  ];
25
60
 
26
- const STRUCTURED_COMMANDS = apiProviderCommands();
61
+ const STRUCTURED_COMMANDS = apiProviderCommands({ writeCommandsImplemented: true });
27
62
 
28
63
  export function giteaToken() {
29
64
  return process.env.GITEA_TOKEN || null;
@@ -119,23 +154,45 @@ export async function giteaFetch(config, parsed, path, options = {}) {
119
154
  });
120
155
  }
121
156
 
122
- const MAX_CHECK_PAGES = 50;
123
- const GITEA_PAGE_SIZE = 100;
157
+ export async function giteaFetchWithMeta(config, parsed, path, options = {}) {
158
+ const token = requireToken();
159
+ const url = `${apiBase(config, parsed)}${path}`;
160
+ return fetchJsonWithMeta(url, {
161
+ ...options,
162
+ headers: { ...authHeaders(token), ...(options.headers || {}) },
163
+ });
164
+ }
165
+
166
+ const MAX_CHECK_PAGES = MAX_CHECK_STATUS_PAGES;
167
+ const GITEA_PAGE_SIZE = DEFAULT_OPEN_PULL_LIST_PAGE_SIZE;
168
+
169
+ function idempotencyScanIncompleteError(pagesScanned, pageSizeUsed) {
170
+ return forgeError(
171
+ ERROR_CODES.IDEMPOTENCY_SCAN_INCOMPLETE,
172
+ 'Cannot prove no open pull exists for head+base within scan limit; use cr inventory or open manually',
173
+ null,
174
+ {
175
+ idempotency_scan: {
176
+ pages: pagesScanned,
177
+ max_pages: MAX_OPEN_PULL_IDEMPOTENCY_PAGES,
178
+ page_size: pageSizeUsed,
179
+ },
180
+ },
181
+ );
182
+ }
124
183
 
125
184
  export async function giteaFetchPaginated(config, parsed, path) {
126
- const all = [];
127
- for (let page = 1; page <= MAX_CHECK_PAGES; page += 1) {
128
- const separator = path.includes('?') ? '&' : '?';
129
- const body = await giteaFetch(
130
- config,
131
- parsed,
132
- `${path}${separator}limit=${GITEA_PAGE_SIZE}&page=${page}`,
133
- );
134
- const items = Array.isArray(body) ? body : [];
135
- all.push(...items);
136
- if (items.length < GITEA_PAGE_SIZE) break;
137
- }
138
- return all;
185
+ return paginateCheckStatusPages({
186
+ fetchPage: async ({ page, limit }) => {
187
+ const separator = path.includes('?') ? '&' : '?';
188
+ const body = await giteaFetch(
189
+ config,
190
+ parsed,
191
+ `${path}${separator}limit=${limit}&page=${page}`,
192
+ );
193
+ return Array.isArray(body) ? body : [];
194
+ },
195
+ });
139
196
  }
140
197
 
141
198
  export function normalizeGiteaStatusState(state) {
@@ -150,6 +207,36 @@ export function normalizeGiteaStatusState(state) {
150
207
  return 'unknown';
151
208
  }
152
209
 
210
+ function giteaStatusRecordOrder(a, b) {
211
+ const aUpdated = Date.parse(a.updated_at ?? '') || 0;
212
+ const bUpdated = Date.parse(b.updated_at ?? '') || 0;
213
+ if (aUpdated !== bUpdated) return aUpdated - bUpdated;
214
+ const aId = Number(a.id) || 0;
215
+ const bId = Number(b.id) || 0;
216
+ return aId - bId;
217
+ }
218
+
219
+ export function dedupeGiteaStatusRecords(records) {
220
+ const latestByContext = new Map();
221
+ for (const record of records) {
222
+ const context = record?.context;
223
+ if (context == null || context === '') continue;
224
+ const existing = latestByContext.get(context);
225
+ if (!existing || giteaStatusRecordOrder(record, existing) > 0) {
226
+ latestByContext.set(context, record);
227
+ }
228
+ }
229
+ return Array.from(latestByContext.values());
230
+ }
231
+
232
+ export function mapGiteaCommitStatuses(records) {
233
+ return dedupeGiteaStatusRecords(records).map((s) => ({
234
+ context: sanitizeField(s.context),
235
+ state: normalizeGiteaStatusState(s.status ?? s.state),
236
+ description: sanitizeField(s.description),
237
+ }));
238
+ }
239
+
153
240
  export function normalizeGiteaPrState(state) {
154
241
  const normalized = String(state ?? '').toLowerCase();
155
242
  if (normalized === 'open') return 'open';
@@ -173,15 +260,35 @@ export async function repoStatus(ctx) {
173
260
  }
174
261
 
175
262
  export function providerCapabilities() {
263
+ const check_sources = ['commit_statuses'];
176
264
  return {
177
265
  commands: STRUCTURED_COMMANDS,
178
266
  auth_envs: ['GITEA_TOKEN'],
179
- check_sources: ['commit_statuses'],
267
+ check_sources,
180
268
  mergeability_confidence: 'direct',
181
269
  host_binding: 'verified_remote_host',
182
270
  pagination: 'supported',
183
- write_support: false,
271
+ write_support: true,
272
+ write_commands: ['cr_open'],
184
273
  ...forgeIngestCapabilityFacts(),
274
+ ...checkPaginationCapabilityFacts({
275
+ strategy: 'offset_limit',
276
+ pageSizeParam: 'limit',
277
+ sourceCount: check_sources.length,
278
+ }),
279
+ ...idempotencyScanCapabilityFacts(),
280
+ ...openPullListCapabilityFacts({
281
+ totalCountSource: 'response_header',
282
+ totalCountHeader: 'X-Total-Count',
283
+ sliceSortNotes: {
284
+ recent_created:
285
+ 'sort=oldest; fetches tail page when total exceeds limit; page reversed for newest-first',
286
+ number_asc:
287
+ 'full-list collect within compliant_max when total exceeds limit, then client sort',
288
+ number_desc:
289
+ 'full-list collect within compliant_max when total exceeds limit, then client sort',
290
+ },
291
+ }),
185
292
  };
186
293
  }
187
294
 
@@ -214,6 +321,284 @@ export async function getPull(ctx, { number }) {
214
321
  return giteaFetch(ctx.config, ctx.parsed, repoApiPath(ctx.config, 'pulls', number));
215
322
  }
216
323
 
324
+ /** Paginated open-pull scan for idempotent cr open; fail-closed when scan cap prevents proof of absence. */
325
+ export async function findOpenPullByHeadBase(ctx, head, base) {
326
+ requireToken();
327
+ const path = `${repoApiPath(ctx.config, 'pulls')}?state=open`;
328
+ const pageSep = path.includes('?') ? '&' : '?';
329
+ let activeLimit = GITEA_PAGE_SIZE;
330
+
331
+ for (let page = 1; page <= MAX_OPEN_PULL_IDEMPOTENCY_PAGES; page += 1) {
332
+ const { items, usedLimit } = await fetchPageWithIngestBackoff(
333
+ async ({ page: pageNum, limit }) => {
334
+ const body = await giteaFetch(
335
+ ctx.config,
336
+ ctx.parsed,
337
+ `${path}${pageSep}limit=${limit}&page=${pageNum}`,
338
+ );
339
+ if (!Array.isArray(body)) {
340
+ throw Object.assign(new Error('Provider returned non-array open pull list'), {
341
+ forgeError: forgeError(
342
+ ERROR_CODES.UNPARSEABLE_PROVIDER_OUTPUT,
343
+ 'Provider returned non-array open pull list',
344
+ ),
345
+ });
346
+ }
347
+ return body;
348
+ },
349
+ page,
350
+ activeLimit,
351
+ );
352
+ activeLimit = usedLimit;
353
+
354
+ const match =
355
+ items.find(
356
+ (pr) =>
357
+ String(pr?.state ?? '').toLowerCase() === 'open' &&
358
+ pr?.head?.ref === head &&
359
+ pr?.base?.ref === base,
360
+ ) ?? null;
361
+ if (match) return match;
362
+ if (items.length < usedLimit) return null;
363
+ if (page === MAX_OPEN_PULL_IDEMPOTENCY_PAGES) {
364
+ throw Object.assign(new Error('Open pull idempotency scan incomplete'), {
365
+ forgeError: idempotencyScanIncompleteError(page, usedLimit),
366
+ });
367
+ }
368
+ }
369
+ return null;
370
+ }
371
+
372
+ export async function crOpen(ctx, { head, base, title, body: prBody }) {
373
+ assertGitRef(head, 'head');
374
+ assertGitRef(base, 'base');
375
+ if (!title || typeof title !== 'string' || !title.trim()) {
376
+ throw Object.assign(new Error('--title required'), {
377
+ forgeError: forgeError(ERROR_CODES.INVALID_ARGS, '--title required for cr open'),
378
+ });
379
+ }
380
+ const payload = {
381
+ title: sanitizeField(title),
382
+ head: sanitizeField(head),
383
+ base: sanitizeField(base),
384
+ };
385
+ if (prBody != null && String(prBody).trim() !== '') {
386
+ payload.body = sanitizeField(String(prBody));
387
+ }
388
+ const existing = await findOpenPullByHeadBase(ctx, payload.head, payload.base);
389
+ if (existing) {
390
+ return buildChangeRequestOpenedBody(existing, { head, base, title }, { reusedExisting: true });
391
+ }
392
+ const pull = await giteaFetch(ctx.config, ctx.parsed, repoApiPath(ctx.config, 'pulls'), {
393
+ method: 'POST',
394
+ headers: { 'Content-Type': 'application/json' },
395
+ body: JSON.stringify(payload),
396
+ });
397
+ return buildChangeRequestOpenedBody(pull, { head, base, title });
398
+ }
399
+
400
+ const GITEA_OPEN_PULL_COMPLIANT_MAX =
401
+ DEFAULT_OPEN_PULL_LIST_PAGE_SIZE * MAX_CHECK_STATUS_PAGES;
402
+
403
+ async function probeGiteaOpenPullPageOne(ctx, retainMax, sliceSort) {
404
+ const maxTrusted = GITEA_OPEN_PULL_COMPLIANT_MAX * 2;
405
+ let path = `${repoApiPath(ctx.config, 'pulls')}?state=open`;
406
+ path = appendSortQuery(path, giteaOpenPullSortQuery(sliceSort));
407
+ const pageSep = path.includes('?') ? '&' : '?';
408
+ const requestLimit = Math.min(retainMax, GITEA_PAGE_SIZE);
409
+ try {
410
+ const { body, headers } = await giteaFetchWithMeta(
411
+ ctx.config,
412
+ ctx.parsed,
413
+ `${path}${pageSep}limit=${requestLimit}&page=1`,
414
+ );
415
+ if (!Array.isArray(body)) return null;
416
+ const totalCount = parseTotalCountHeader(headers, 'X-Total-Count', { maxTrusted });
417
+ if (totalCount == null) return null;
418
+ const listTruncated = totalCount > GITEA_OPEN_PULL_COMPLIANT_MAX;
419
+ return { body, totalCount, listTruncated, requestLimit };
420
+ } catch {
421
+ return null;
422
+ }
423
+ }
424
+
425
+ function buildGiteaOpenPullMetaFromPage(body, retainMax, sliceSort, totalCount, listTruncated) {
426
+ const pageItems = prepareGiteaOpenPullPageItems(body, sliceSort);
427
+ let numbers = orderOpenPullNumbers(pageItems, (pr) => pr?.number, sliceSort);
428
+ if (numbers.length > retainMax) numbers = numbers.slice(0, retainMax);
429
+ return buildOpenPullListMeta({
430
+ totalCount,
431
+ numbers,
432
+ listTruncated,
433
+ sliceSort,
434
+ });
435
+ }
436
+
437
+ async function fetchGiteaRecentCreatedTailSlice(ctx, retainMax, sliceSort, totalCount) {
438
+ const tailPage = giteaRecentCreatedTailPage(totalCount, GITEA_PAGE_SIZE);
439
+ let path = `${repoApiPath(ctx.config, 'pulls')}?state=open`;
440
+ path = appendSortQuery(path, giteaOpenPullSortQuery(sliceSort));
441
+ const pageSep = path.includes('?') ? '&' : '?';
442
+ let body;
443
+ try {
444
+ body = await giteaFetch(
445
+ ctx.config,
446
+ ctx.parsed,
447
+ `${path}${pageSep}limit=${GITEA_PAGE_SIZE}&page=${tailPage}`,
448
+ );
449
+ } catch {
450
+ return null;
451
+ }
452
+ if (!Array.isArray(body) || body.length === 0) return null;
453
+ return buildGiteaOpenPullMetaFromPage(body, retainMax, sliceSort, totalCount, false);
454
+ }
455
+
456
+ function giteaProbePaginationOpts(probe, extra = {}) {
457
+ const { body, totalCount, requestLimit } = probe;
458
+ return {
459
+ trustedTotalCount: totalCount,
460
+ seededFirstPage: { items: body, usedLimit: requestLimit },
461
+ ...extra,
462
+ };
463
+ }
464
+
465
+ async function paginateGiteaOpenPullList(ctx, opts, sliceSort, paginationOpts = {}) {
466
+ const {
467
+ trustedTotalCount = null,
468
+ numberSortFullCollect = false,
469
+ seededFirstPage = null,
470
+ startPage = 1,
471
+ maxPages = MAX_CHECK_STATUS_PAGES,
472
+ suppressFinalPageProbe = false,
473
+ } = paginationOpts;
474
+ const listLimit =
475
+ opts.limit != null && Number.isInteger(Number(opts.limit)) && Number(opts.limit) > 0
476
+ ? Number(opts.limit)
477
+ : null;
478
+ const retainMax =
479
+ listLimit == null &&
480
+ opts.retain_max != null &&
481
+ Number.isInteger(Number(opts.retain_max)) &&
482
+ Number(opts.retain_max) > 0
483
+ ? Number(opts.retain_max)
484
+ : null;
485
+ const pageSize =
486
+ listLimit != null ? Math.min(listLimit, GITEA_PAGE_SIZE) : GITEA_PAGE_SIZE;
487
+ let path = `${repoApiPath(ctx.config, 'pulls')}?state=open`;
488
+ path = appendSortQuery(path, giteaOpenPullSortQuery(sliceSort));
489
+ const pageSep = path.includes('?') ? '&' : '?';
490
+ const effectiveRetainMax = numberSortFullCollect ? null : retainMax;
491
+ const {
492
+ items: all,
493
+ list_truncated: listTruncated,
494
+ entry_count: entryCount,
495
+ walked_count: walkedCount,
496
+ } = await paginateOffsetListPages({
497
+ pageSize,
498
+ listLimit,
499
+ retainMax: effectiveRetainMax,
500
+ trustedEntryCount: trustedTotalCount,
501
+ seededFirstPage,
502
+ startPage,
503
+ maxPages,
504
+ suppressFinalPageProbe,
505
+ ...(listLimit != null && pageSize < listLimit ? { maxPagesTruncatesWithLimit: true } : {}),
506
+ fetchPage: async ({ page, limit }) => {
507
+ const body = await giteaFetch(
508
+ ctx.config,
509
+ ctx.parsed,
510
+ `${path}${pageSep}limit=${limit}&page=${page}`,
511
+ );
512
+ return Array.isArray(body) ? body : [];
513
+ },
514
+ });
515
+ let numbers = orderOpenPullNumbers(
516
+ prepareGiteaOpenPullPageItems(all, sliceSort),
517
+ (pr) => pr?.number,
518
+ sliceSort,
519
+ );
520
+ const outputCap = listLimit ?? retainMax;
521
+ if (outputCap != null && numbers.length > outputCap) {
522
+ numbers = numbers.slice(0, outputCap);
523
+ }
524
+ return {
525
+ numbers,
526
+ list_truncated: resolveListTruncatedWithTrustedTotal({
527
+ listTruncated,
528
+ trustedTotalCount,
529
+ walkedCount,
530
+ fullCollect: numberSortFullCollect,
531
+ }),
532
+ ...(entryCount != null ? { entry_count: entryCount } : {}),
533
+ slice_sort: sliceSort,
534
+ };
535
+ }
536
+
537
+ export async function listOpenPullsWithMeta(ctx, opts = {}) {
538
+ requireToken();
539
+ const sliceSort = normalizeCrInventorySort(opts.sort ?? DEFAULT_CR_INVENTORY_SLICE_SORT);
540
+ if (!isCrInventoryFastPathEligible(opts)) {
541
+ return paginateGiteaOpenPullList(ctx, opts, sliceSort);
542
+ }
543
+
544
+ const retainMax = Number(opts.retain_max);
545
+ const probe = await probeGiteaOpenPullPageOne(ctx, retainMax, sliceSort);
546
+ if (!probe) {
547
+ return paginateGiteaOpenPullList(ctx, opts, sliceSort);
548
+ }
549
+
550
+ const { body, totalCount, listTruncated, requestLimit } = probe;
551
+
552
+ if (listTruncated) {
553
+ if (body.length === 0) {
554
+ return paginateGiteaOpenPullList(ctx, opts, sliceSort, giteaProbePaginationOpts(probe));
555
+ }
556
+ return buildGiteaOpenPullMetaFromPage(body, retainMax, sliceSort, totalCount, true);
557
+ }
558
+
559
+ if (
560
+ sliceSort === 'recent_created' &&
561
+ !isRecentCreatedFastPathEligible(totalCount, retainMax, sliceSort, 'gitea-api')
562
+ ) {
563
+ const tail = await fetchGiteaRecentCreatedTailSlice(ctx, retainMax, sliceSort, totalCount);
564
+ if (tail) return tail;
565
+ const tailRetry = await fetchGiteaRecentCreatedTailSlice(ctx, retainMax, sliceSort, totalCount);
566
+ if (tailRetry) return tailRetry;
567
+ const tailPage = giteaRecentCreatedTailPage(totalCount, GITEA_PAGE_SIZE);
568
+ return paginateGiteaOpenPullList(ctx, opts, sliceSort, {
569
+ trustedTotalCount: totalCount,
570
+ startPage: tailPage,
571
+ maxPages: tailPage,
572
+ suppressFinalPageProbe: true,
573
+ });
574
+ }
575
+
576
+ if (
577
+ isRecentCreatedFastPathEligible(totalCount, retainMax, sliceSort, 'gitea-api') &&
578
+ isNumberSortFastPathEligible(totalCount, retainMax, sliceSort) &&
579
+ validateFastPathPageLength(totalCount, requestLimit, body.length)
580
+ ) {
581
+ return buildGiteaOpenPullMetaFromPage(body, retainMax, sliceSort, totalCount, false);
582
+ }
583
+
584
+ const numberSortFullCollect = isNumberSortFullCollectRequired(totalCount, retainMax, sliceSort);
585
+ return paginateGiteaOpenPullList(
586
+ ctx,
587
+ opts,
588
+ sliceSort,
589
+ giteaProbePaginationOpts(probe, { numberSortFullCollect }),
590
+ );
591
+ }
592
+
593
+ export async function listOpenPulls(ctx, opts = {}) {
594
+ const meta = await listOpenPullsWithMeta(ctx, opts);
595
+ return meta.numbers;
596
+ }
597
+
598
+ export async function crInventorySlice(ctx, opts = {}) {
599
+ return crInventory(ctx, { listOpenPulls, listOpenPullsWithMeta, prView, prChecks }, opts);
600
+ }
601
+
217
602
  function mergeability(pr) {
218
603
  if (pr.mergeable === true) return 'clean';
219
604
  if (pr.mergeable === false) return 'conflicted';
@@ -255,18 +640,19 @@ export async function prChecks(ctx, opts) {
255
640
  forgeError: forgeError(ERROR_CODES.MISSING_REF, 'Could not determine head SHA for checks'),
256
641
  });
257
642
  }
258
- const statusRecords = await giteaFetchPaginated(
643
+ const { items: statusRecords, truncated: checks_truncated } = await giteaFetchPaginated(
259
644
  ctx.config,
260
645
  ctx.parsed,
261
646
  repoApiPath(ctx.config, 'commits', sha, 'statuses'),
262
647
  );
263
- const mapped = statusRecords.map((s) => ({
264
- context: sanitizeField(s.context),
265
- state: normalizeGiteaStatusState(s.state),
266
- description: sanitizeField(s.description),
267
- }));
648
+ const mapped = mapGiteaCommitStatuses(statusRecords);
268
649
  const conclusion = summarizeChecks(mapped);
269
- return { head_sha: sha, check_conclusion: conclusion, statuses: mapped };
650
+ return {
651
+ head_sha: sha,
652
+ check_conclusion: conclusion,
653
+ checks_truncated,
654
+ statuses: mapped,
655
+ };
270
656
  }
271
657
 
272
658
  export function summarizeChecks(statuses) {
@@ -280,18 +666,7 @@ export function summarizeChecks(statuses) {
280
666
  export async function mergePlan(ctx, opts) {
281
667
  const view = await prView(ctx, opts);
282
668
  const checks = await prChecks(ctx, { number: view.pr_number });
283
- const blockers = [];
284
- if (view.mergeability === 'conflicted') blockers.push('merge_conflict');
285
- if (view.state !== 'open') blockers.push('pr_not_open');
286
- if (checks.check_conclusion === 'failure') blockers.push('checks_failed');
287
- if (checks.check_conclusion === 'missing') blockers.push('checks_missing');
288
- if (checks.check_conclusion === 'pending') blockers.push('checks_pending');
289
- return {
290
- pr_number: view.pr_number,
291
- mergeability: view.mergeability,
292
- checks_conclusion: checks.check_conclusion,
293
- blockers,
294
- };
669
+ return buildMergePlanBodyFromFacts(ctx, view, checks, opts);
295
670
  }
296
671
 
297
672
  export async function syncPlan(ctx, remoteName = 'origin') {
@@ -326,8 +701,12 @@ export const provider = {
326
701
  providerCapabilities,
327
702
  repoStatus,
328
703
  refsCompare,
704
+ refsInventory,
705
+ listOpenPulls,
706
+ crInventory: crInventorySlice,
329
707
  prView,
330
708
  prChecks,
331
709
  mergePlan,
332
710
  syncPlan,
711
+ crOpen,
333
712
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remogram/provider-gitea-api",
3
- "version": "0.1.0-beta.2",
3
+ "version": "0.1.0-beta.4",
4
4
  "description": "Gitea REST API forge provider for remogram",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -22,6 +22,6 @@
22
22
  "node": ">=20"
23
23
  },
24
24
  "dependencies": {
25
- "@remogram/core": "0.1.0-beta.2"
25
+ "@remogram/core": "0.1.0-beta.4"
26
26
  }
27
27
  }