@corigin/cli 0.1.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.
Files changed (2) hide show
  1. package/dist/main.js +1551 -0
  2. package/package.json +32 -0
package/dist/main.js ADDED
@@ -0,0 +1,1551 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/main.ts
4
+ import { spawnSync } from "node:child_process";
5
+ import { realpathSync } from "node:fs";
6
+ import { fileURLToPath } from "node:url";
7
+ import { Command, CommanderError, InvalidArgumentError } from "commander";
8
+ import { z as z3 } from "zod/v4";
9
+
10
+ // src/lib/config.ts
11
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
12
+ import { homedir } from "node:os";
13
+ import path from "node:path";
14
+ import { parse, stringify } from "smol-toml";
15
+ import { z } from "zod/v4";
16
+ var defaultProfileName = "default";
17
+ var defaultConfigDir = path.join(homedir(), ".config", "corigin");
18
+ var defaultProfileConfig = {
19
+ api_url: "https://api.corigin.dev",
20
+ web_url: "https://corigin.dev"
21
+ };
22
+ var profileNameSchema = z.string().min(1).regex(/^[A-Za-z0-9_.-]+$/u);
23
+ var profileConfigSchema = z.object({
24
+ api_url: z.url(),
25
+ web_url: z.url()
26
+ }).strict();
27
+ var coriginConfigSchema = z.object({
28
+ profile: profileNameSchema.optional(),
29
+ profiles: z.record(profileNameSchema, profileConfigSchema).optional()
30
+ }).strict();
31
+ function configFilePath(configDir) {
32
+ return path.join(configDir, "config.toml");
33
+ }
34
+ async function readConfig(configDir) {
35
+ const source = await readFile(configFilePath(configDir), "utf8").catch((error) => {
36
+ if (isNotFoundError(error)) return null;
37
+ throw error;
38
+ });
39
+ if (source === null) return {};
40
+ return coriginConfigSchema.parse(parse(source));
41
+ }
42
+ async function writeConfig(configDir, config) {
43
+ await mkdir(configDir, { recursive: true, mode: 448 });
44
+ await writeFile(configFilePath(configDir), stringify(coriginConfigSchema.parse(config)), {
45
+ mode: 384
46
+ });
47
+ }
48
+ function resolveProfileName(config, explicitProfile) {
49
+ if (explicitProfile !== void 0) return profileNameSchema.parse(explicitProfile);
50
+ return config.profile ?? defaultProfileName;
51
+ }
52
+ function setProfileConfig(config, profileName, profileConfig) {
53
+ profileNameSchema.parse(profileName);
54
+ return {
55
+ ...config,
56
+ profile: profileName,
57
+ profiles: {
58
+ ...config.profiles,
59
+ [profileName]: profileConfigSchema.parse(profileConfig)
60
+ }
61
+ };
62
+ }
63
+ function isNotFoundError(error) {
64
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
65
+ }
66
+
67
+ // src/lib/credentials.ts
68
+ import { chmod, mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
69
+ import path2 from "node:path";
70
+ import { parse as parse2, stringify as stringify2 } from "smol-toml";
71
+ import { z as z2 } from "zod/v4";
72
+ var profileCredentialSchema = z2.object({
73
+ credential: z2.string().min(1)
74
+ }).strict();
75
+ var coriginCredentialsSchema = z2.object({
76
+ profiles: z2.record(profileNameSchema, profileCredentialSchema).optional()
77
+ }).strict();
78
+ function credentialsFilePath(configDir) {
79
+ return path2.join(configDir, "credentials.toml");
80
+ }
81
+ function legacyCredentialsFilePath(configDir) {
82
+ return path2.join(configDir, "credentials.json");
83
+ }
84
+ async function readCredentials(configDir) {
85
+ const source = await readFile2(credentialsFilePath(configDir), "utf8").catch((error) => {
86
+ if (isNotFoundError2(error)) return null;
87
+ throw error;
88
+ });
89
+ if (source === null) return {};
90
+ return coriginCredentialsSchema.parse(parse2(source));
91
+ }
92
+ async function writeCredentials(configDir, credentials) {
93
+ await mkdir2(configDir, { recursive: true, mode: 448 });
94
+ const filePath = credentialsFilePath(configDir);
95
+ await writeFile2(filePath, stringify2(coriginCredentialsSchema.parse(credentials)), {
96
+ mode: 384
97
+ });
98
+ await chmod(filePath, 384).catch(() => void 0);
99
+ }
100
+ async function writeProfileCredential(configDir, profileName, credential) {
101
+ profileNameSchema.parse(profileName);
102
+ const existing = await readCredentials(configDir);
103
+ await writeCredentials(configDir, {
104
+ ...existing,
105
+ profiles: {
106
+ ...existing.profiles,
107
+ [profileName]: profileCredentialSchema.parse({ credential })
108
+ }
109
+ });
110
+ }
111
+ async function readProfileCredential(configDir, profileName) {
112
+ profileNameSchema.parse(profileName);
113
+ return (await readCredentials(configDir)).profiles?.[profileName];
114
+ }
115
+ async function migrateLegacyCredential(configDir) {
116
+ const source = await readFile2(legacyCredentialsFilePath(configDir), "utf8").catch(
117
+ (error) => {
118
+ if (isNotFoundError2(error)) return null;
119
+ throw error;
120
+ }
121
+ );
122
+ if (source === null) return void 0;
123
+ const parsed = legacyCredentialsSchema.parse(JSON.parse(source));
124
+ const productionCredentials = parsed.credentials.filter(
125
+ (credential) => credential.apiUrl === "https://api.corigin.dev"
126
+ );
127
+ if (productionCredentials.length === 0) return void 0;
128
+ if (productionCredentials.length > 1) {
129
+ throw new Error("Legacy credentials are ambiguous. Run corigin login --profile <name>.");
130
+ }
131
+ return { credential: productionCredentials[0].credential };
132
+ }
133
+ var legacyCredentialsSchema = z2.object({
134
+ credentials: z2.array(
135
+ z2.object({
136
+ apiUrl: z2.string(),
137
+ workspaceId: z2.string(),
138
+ workspaceName: z2.string(),
139
+ credential: z2.string().min(1)
140
+ })
141
+ ).default([])
142
+ });
143
+ function isNotFoundError2(error) {
144
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
145
+ }
146
+
147
+ // src/lib/generated/repo-api-client/core/serverSentEvents.gen.ts
148
+ function createSseClient({
149
+ onRequest,
150
+ onSseError,
151
+ onSseEvent,
152
+ responseTransformer,
153
+ responseValidator,
154
+ sseDefaultRetryDelay,
155
+ sseMaxRetryAttempts,
156
+ sseMaxRetryDelay,
157
+ sseSleepFn,
158
+ url,
159
+ ...options
160
+ }) {
161
+ let lastEventId;
162
+ const sleep2 = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
163
+ const createStream = async function* () {
164
+ let retryDelay = sseDefaultRetryDelay ?? 3e3;
165
+ let attempt = 0;
166
+ const signal = options.signal ?? new AbortController().signal;
167
+ while (true) {
168
+ if (signal.aborted) break;
169
+ attempt++;
170
+ const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
171
+ if (lastEventId !== void 0) {
172
+ headers.set("Last-Event-ID", lastEventId);
173
+ }
174
+ try {
175
+ const requestInit = {
176
+ redirect: "follow",
177
+ ...options,
178
+ body: options.serializedBody,
179
+ headers,
180
+ signal
181
+ };
182
+ let request = new Request(url, requestInit);
183
+ if (onRequest) {
184
+ request = await onRequest(url, requestInit);
185
+ }
186
+ const _fetch = options.fetch ?? globalThis.fetch;
187
+ const response = await _fetch(request);
188
+ if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
189
+ if (!response.body) throw new Error("No body in SSE response");
190
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
191
+ let buffer = "";
192
+ const abortHandler = () => {
193
+ try {
194
+ reader.cancel();
195
+ } catch {
196
+ }
197
+ };
198
+ signal.addEventListener("abort", abortHandler);
199
+ try {
200
+ while (true) {
201
+ const { done, value } = await reader.read();
202
+ if (done) break;
203
+ buffer += value;
204
+ buffer = buffer.replace(/\r\n?/g, "\n");
205
+ const chunks = buffer.split("\n\n");
206
+ buffer = chunks.pop() ?? "";
207
+ for (const chunk of chunks) {
208
+ const lines = chunk.split("\n");
209
+ const dataLines = [];
210
+ let eventName;
211
+ for (const line of lines) {
212
+ if (line.startsWith("data:")) {
213
+ dataLines.push(line.replace(/^data:\s*/, ""));
214
+ } else if (line.startsWith("event:")) {
215
+ eventName = line.replace(/^event:\s*/, "");
216
+ } else if (line.startsWith("id:")) {
217
+ lastEventId = line.replace(/^id:\s*/, "");
218
+ } else if (line.startsWith("retry:")) {
219
+ const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
220
+ if (!Number.isNaN(parsed)) {
221
+ retryDelay = parsed;
222
+ }
223
+ }
224
+ }
225
+ let data;
226
+ let parsedJson = false;
227
+ if (dataLines.length) {
228
+ const rawData = dataLines.join("\n");
229
+ try {
230
+ data = JSON.parse(rawData);
231
+ parsedJson = true;
232
+ } catch {
233
+ data = rawData;
234
+ }
235
+ }
236
+ if (parsedJson) {
237
+ if (responseValidator) {
238
+ await responseValidator(data);
239
+ }
240
+ if (responseTransformer) {
241
+ data = await responseTransformer(data);
242
+ }
243
+ }
244
+ onSseEvent?.({
245
+ data,
246
+ event: eventName,
247
+ id: lastEventId,
248
+ retry: retryDelay
249
+ });
250
+ if (dataLines.length) {
251
+ yield data;
252
+ }
253
+ }
254
+ }
255
+ } finally {
256
+ signal.removeEventListener("abort", abortHandler);
257
+ reader.releaseLock();
258
+ }
259
+ break;
260
+ } catch (error) {
261
+ onSseError?.(error);
262
+ if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
263
+ break;
264
+ }
265
+ const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
266
+ await sleep2(backoff);
267
+ }
268
+ }
269
+ };
270
+ const stream = createStream();
271
+ return { stream };
272
+ }
273
+
274
+ // src/lib/generated/repo-api-client/core/pathSerializer.gen.ts
275
+ var separatorArrayExplode = (style) => {
276
+ switch (style) {
277
+ case "label":
278
+ return ".";
279
+ case "matrix":
280
+ return ";";
281
+ case "simple":
282
+ return ",";
283
+ default:
284
+ return "&";
285
+ }
286
+ };
287
+ var separatorArrayNoExplode = (style) => {
288
+ switch (style) {
289
+ case "form":
290
+ return ",";
291
+ case "pipeDelimited":
292
+ return "|";
293
+ case "spaceDelimited":
294
+ return "%20";
295
+ default:
296
+ return ",";
297
+ }
298
+ };
299
+ var separatorObjectExplode = (style) => {
300
+ switch (style) {
301
+ case "label":
302
+ return ".";
303
+ case "matrix":
304
+ return ";";
305
+ case "simple":
306
+ return ",";
307
+ default:
308
+ return "&";
309
+ }
310
+ };
311
+ var serializeArrayParam = ({
312
+ allowReserved,
313
+ explode,
314
+ name,
315
+ style,
316
+ value
317
+ }) => {
318
+ if (!explode) {
319
+ const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
320
+ switch (style) {
321
+ case "label":
322
+ return `.${joinedValues2}`;
323
+ case "matrix":
324
+ return `;${name}=${joinedValues2}`;
325
+ case "simple":
326
+ return joinedValues2;
327
+ default:
328
+ return `${name}=${joinedValues2}`;
329
+ }
330
+ }
331
+ const separator = separatorArrayExplode(style);
332
+ const joinedValues = value.map((v) => {
333
+ if (style === "label" || style === "simple") {
334
+ return allowReserved ? v : encodeURIComponent(v);
335
+ }
336
+ return serializePrimitiveParam({
337
+ allowReserved,
338
+ name,
339
+ value: v
340
+ });
341
+ }).join(separator);
342
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
343
+ };
344
+ var serializePrimitiveParam = ({
345
+ allowReserved,
346
+ name,
347
+ value
348
+ }) => {
349
+ if (value === void 0 || value === null) {
350
+ return "";
351
+ }
352
+ if (typeof value === "object") {
353
+ throw new Error(
354
+ "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
355
+ );
356
+ }
357
+ return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
358
+ };
359
+ var serializeObjectParam = ({
360
+ allowReserved,
361
+ explode,
362
+ name,
363
+ style,
364
+ value,
365
+ valueOnly
366
+ }) => {
367
+ if (value instanceof Date) {
368
+ return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
369
+ }
370
+ if (style !== "deepObject" && !explode) {
371
+ let values = [];
372
+ Object.entries(value).forEach(([key, v]) => {
373
+ values = [...values, key, allowReserved ? v : encodeURIComponent(v)];
374
+ });
375
+ const joinedValues2 = values.join(",");
376
+ switch (style) {
377
+ case "form":
378
+ return `${name}=${joinedValues2}`;
379
+ case "label":
380
+ return `.${joinedValues2}`;
381
+ case "matrix":
382
+ return `;${name}=${joinedValues2}`;
383
+ default:
384
+ return joinedValues2;
385
+ }
386
+ }
387
+ const separator = separatorObjectExplode(style);
388
+ const joinedValues = Object.entries(value).map(
389
+ ([key, v]) => serializePrimitiveParam({
390
+ allowReserved,
391
+ name: style === "deepObject" ? `${name}[${key}]` : key,
392
+ value: v
393
+ })
394
+ ).join(separator);
395
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
396
+ };
397
+
398
+ // src/lib/generated/repo-api-client/core/utils.gen.ts
399
+ var PATH_PARAM_RE = /\{[^{}]+\}/g;
400
+ var defaultPathSerializer = ({ path: path3, url: _url }) => {
401
+ let url = _url;
402
+ const matches = _url.match(PATH_PARAM_RE);
403
+ if (matches) {
404
+ for (const match of matches) {
405
+ let explode = false;
406
+ let name = match.substring(1, match.length - 1);
407
+ let style = "simple";
408
+ if (name.endsWith("*")) {
409
+ explode = true;
410
+ name = name.substring(0, name.length - 1);
411
+ }
412
+ if (name.startsWith(".")) {
413
+ name = name.substring(1);
414
+ style = "label";
415
+ } else if (name.startsWith(";")) {
416
+ name = name.substring(1);
417
+ style = "matrix";
418
+ }
419
+ const value = path3[name];
420
+ if (value === void 0 || value === null) {
421
+ continue;
422
+ }
423
+ if (Array.isArray(value)) {
424
+ url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
425
+ continue;
426
+ }
427
+ if (typeof value === "object") {
428
+ url = url.replace(
429
+ match,
430
+ serializeObjectParam({
431
+ explode,
432
+ name,
433
+ style,
434
+ value,
435
+ valueOnly: true
436
+ })
437
+ );
438
+ continue;
439
+ }
440
+ if (style === "matrix") {
441
+ url = url.replace(
442
+ match,
443
+ `;${serializePrimitiveParam({
444
+ name,
445
+ value
446
+ })}`
447
+ );
448
+ continue;
449
+ }
450
+ const replaceValue = encodeURIComponent(
451
+ style === "label" ? `.${value}` : value
452
+ );
453
+ url = url.replace(match, replaceValue);
454
+ }
455
+ }
456
+ return url;
457
+ };
458
+ var getUrl = ({
459
+ baseUrl,
460
+ path: path3,
461
+ query,
462
+ querySerializer,
463
+ url: _url
464
+ }) => {
465
+ const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
466
+ let url = (baseUrl ?? "") + pathUrl;
467
+ if (path3) {
468
+ url = defaultPathSerializer({ path: path3, url });
469
+ }
470
+ let search = query ? querySerializer(query) : "";
471
+ if (search.startsWith("?")) {
472
+ search = search.substring(1);
473
+ }
474
+ if (search) {
475
+ url += `?${search}`;
476
+ }
477
+ return url;
478
+ };
479
+ function getValidRequestBody(options) {
480
+ const hasBody = options.body !== void 0;
481
+ const isSerializedBody = hasBody && options.bodySerializer;
482
+ if (isSerializedBody) {
483
+ if ("serializedBody" in options) {
484
+ const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
485
+ return hasSerializedBody ? options.serializedBody : null;
486
+ }
487
+ return options.body !== "" ? options.body : null;
488
+ }
489
+ if (hasBody) {
490
+ return options.body;
491
+ }
492
+ return void 0;
493
+ }
494
+
495
+ // src/lib/generated/repo-api-client/core/auth.gen.ts
496
+ var getAuthToken = async (auth, callback) => {
497
+ const token = typeof callback === "function" ? await callback(auth) : callback;
498
+ if (!token) {
499
+ return;
500
+ }
501
+ if (auth.scheme === "bearer") {
502
+ return `Bearer ${token}`;
503
+ }
504
+ if (auth.scheme === "basic") {
505
+ return `Basic ${btoa(token)}`;
506
+ }
507
+ return token;
508
+ };
509
+
510
+ // src/lib/generated/repo-api-client/core/bodySerializer.gen.ts
511
+ var jsonBodySerializer = {
512
+ bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value)
513
+ };
514
+
515
+ // src/lib/generated/repo-api-client/client/utils.gen.ts
516
+ var createQuerySerializer = ({
517
+ parameters = {},
518
+ ...args
519
+ } = {}) => {
520
+ const querySerializer = (queryParams) => {
521
+ const search = [];
522
+ if (queryParams && typeof queryParams === "object") {
523
+ for (const name in queryParams) {
524
+ const value = queryParams[name];
525
+ if (value === void 0 || value === null) {
526
+ continue;
527
+ }
528
+ const options = parameters[name] || args;
529
+ if (Array.isArray(value)) {
530
+ const serializedArray = serializeArrayParam({
531
+ allowReserved: options.allowReserved,
532
+ explode: true,
533
+ name,
534
+ style: "form",
535
+ value,
536
+ ...options.array
537
+ });
538
+ if (serializedArray) search.push(serializedArray);
539
+ } else if (typeof value === "object") {
540
+ const serializedObject = serializeObjectParam({
541
+ allowReserved: options.allowReserved,
542
+ explode: true,
543
+ name,
544
+ style: "deepObject",
545
+ value,
546
+ ...options.object
547
+ });
548
+ if (serializedObject) search.push(serializedObject);
549
+ } else {
550
+ const serializedPrimitive = serializePrimitiveParam({
551
+ allowReserved: options.allowReserved,
552
+ name,
553
+ value
554
+ });
555
+ if (serializedPrimitive) search.push(serializedPrimitive);
556
+ }
557
+ }
558
+ }
559
+ return search.join("&");
560
+ };
561
+ return querySerializer;
562
+ };
563
+ var getParseAs = (contentType) => {
564
+ if (!contentType) {
565
+ return "stream";
566
+ }
567
+ const cleanContent = contentType.split(";")[0]?.trim();
568
+ if (!cleanContent) {
569
+ return;
570
+ }
571
+ if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
572
+ return "json";
573
+ }
574
+ if (cleanContent === "multipart/form-data") {
575
+ return "formData";
576
+ }
577
+ if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
578
+ return "blob";
579
+ }
580
+ if (cleanContent.startsWith("text/")) {
581
+ return "text";
582
+ }
583
+ return;
584
+ };
585
+ var checkForExistence = (options, name) => {
586
+ if (!name) {
587
+ return false;
588
+ }
589
+ if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
590
+ return true;
591
+ }
592
+ return false;
593
+ };
594
+ var setAuthParams = async ({
595
+ security,
596
+ ...options
597
+ }) => {
598
+ for (const auth of security) {
599
+ if (checkForExistence(options, auth.name)) {
600
+ continue;
601
+ }
602
+ const token = await getAuthToken(auth, options.auth);
603
+ if (!token) {
604
+ continue;
605
+ }
606
+ const name = auth.name ?? "Authorization";
607
+ switch (auth.in) {
608
+ case "query":
609
+ if (!options.query) {
610
+ options.query = {};
611
+ }
612
+ options.query[name] = token;
613
+ break;
614
+ case "cookie":
615
+ options.headers.append("Cookie", `${name}=${token}`);
616
+ break;
617
+ case "header":
618
+ default:
619
+ options.headers.set(name, token);
620
+ break;
621
+ }
622
+ }
623
+ };
624
+ var buildUrl = (options) => getUrl({
625
+ baseUrl: options.baseUrl,
626
+ path: options.path,
627
+ query: options.query,
628
+ querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
629
+ url: options.url
630
+ });
631
+ var mergeConfigs = (a, b) => {
632
+ const config = { ...a, ...b };
633
+ if (config.baseUrl?.endsWith("/")) {
634
+ config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
635
+ }
636
+ config.headers = mergeHeaders(a.headers, b.headers);
637
+ return config;
638
+ };
639
+ var headersEntries = (headers) => {
640
+ const entries = [];
641
+ headers.forEach((value, key) => {
642
+ entries.push([key, value]);
643
+ });
644
+ return entries;
645
+ };
646
+ var mergeHeaders = (...headers) => {
647
+ const mergedHeaders = new Headers();
648
+ for (const header of headers) {
649
+ if (!header) {
650
+ continue;
651
+ }
652
+ const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
653
+ for (const [key, value] of iterator) {
654
+ if (value === null) {
655
+ mergedHeaders.delete(key);
656
+ } else if (Array.isArray(value)) {
657
+ for (const v of value) {
658
+ mergedHeaders.append(key, v);
659
+ }
660
+ } else if (value !== void 0) {
661
+ mergedHeaders.set(
662
+ key,
663
+ typeof value === "object" ? JSON.stringify(value) : value
664
+ );
665
+ }
666
+ }
667
+ }
668
+ return mergedHeaders;
669
+ };
670
+ var Interceptors = class {
671
+ fns = [];
672
+ clear() {
673
+ this.fns = [];
674
+ }
675
+ eject(id) {
676
+ const index = this.getInterceptorIndex(id);
677
+ if (this.fns[index]) {
678
+ this.fns[index] = null;
679
+ }
680
+ }
681
+ exists(id) {
682
+ const index = this.getInterceptorIndex(id);
683
+ return Boolean(this.fns[index]);
684
+ }
685
+ getInterceptorIndex(id) {
686
+ if (typeof id === "number") {
687
+ return this.fns[id] ? id : -1;
688
+ }
689
+ return this.fns.indexOf(id);
690
+ }
691
+ update(id, fn) {
692
+ const index = this.getInterceptorIndex(id);
693
+ if (this.fns[index]) {
694
+ this.fns[index] = fn;
695
+ return id;
696
+ }
697
+ return false;
698
+ }
699
+ use(fn) {
700
+ this.fns.push(fn);
701
+ return this.fns.length - 1;
702
+ }
703
+ };
704
+ var createInterceptors = () => ({
705
+ error: new Interceptors(),
706
+ request: new Interceptors(),
707
+ response: new Interceptors()
708
+ });
709
+ var defaultQuerySerializer = createQuerySerializer({
710
+ allowReserved: false,
711
+ array: {
712
+ explode: true,
713
+ style: "form"
714
+ },
715
+ object: {
716
+ explode: true,
717
+ style: "deepObject"
718
+ }
719
+ });
720
+ var defaultHeaders = {
721
+ "Content-Type": "application/json"
722
+ };
723
+ var createConfig = (override = {}) => ({
724
+ ...jsonBodySerializer,
725
+ headers: defaultHeaders,
726
+ parseAs: "auto",
727
+ querySerializer: defaultQuerySerializer,
728
+ ...override
729
+ });
730
+
731
+ // src/lib/generated/repo-api-client/client/client.gen.ts
732
+ var createClient = (config = {}) => {
733
+ let _config = mergeConfigs(createConfig(), config);
734
+ const getConfig = () => ({ ..._config });
735
+ const setConfig = (config2) => {
736
+ _config = mergeConfigs(_config, config2);
737
+ return getConfig();
738
+ };
739
+ const interceptors = createInterceptors();
740
+ const beforeRequest = async (options) => {
741
+ const opts = {
742
+ ..._config,
743
+ ...options,
744
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
745
+ headers: mergeHeaders(_config.headers, options.headers),
746
+ serializedBody: void 0
747
+ };
748
+ if (opts.security) {
749
+ await setAuthParams({
750
+ ...opts,
751
+ security: opts.security
752
+ });
753
+ }
754
+ if (opts.requestValidator) {
755
+ await opts.requestValidator(opts);
756
+ }
757
+ if (opts.body !== void 0 && opts.bodySerializer) {
758
+ opts.serializedBody = opts.bodySerializer(opts.body);
759
+ }
760
+ if (opts.body === void 0 || opts.serializedBody === "") {
761
+ opts.headers.delete("Content-Type");
762
+ }
763
+ const resolvedOpts = opts;
764
+ const url = buildUrl(resolvedOpts);
765
+ return { opts: resolvedOpts, url };
766
+ };
767
+ const request = async (options) => {
768
+ const throwOnError = options.throwOnError ?? _config.throwOnError;
769
+ const responseStyle = options.responseStyle ?? _config.responseStyle;
770
+ let request2;
771
+ let response;
772
+ try {
773
+ const { opts, url } = await beforeRequest(options);
774
+ const requestInit = {
775
+ redirect: "follow",
776
+ ...opts,
777
+ body: getValidRequestBody(opts)
778
+ };
779
+ request2 = new Request(url, requestInit);
780
+ for (const fn of interceptors.request.fns) {
781
+ if (fn) {
782
+ request2 = await fn(request2, opts);
783
+ }
784
+ }
785
+ const _fetch = opts.fetch;
786
+ response = await _fetch(request2);
787
+ for (const fn of interceptors.response.fns) {
788
+ if (fn) {
789
+ response = await fn(response, request2, opts);
790
+ }
791
+ }
792
+ const result = {
793
+ request: request2,
794
+ response
795
+ };
796
+ if (response.ok) {
797
+ const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
798
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
799
+ let emptyData;
800
+ switch (parseAs) {
801
+ case "arrayBuffer":
802
+ case "blob":
803
+ case "text":
804
+ emptyData = await response[parseAs]();
805
+ break;
806
+ case "formData":
807
+ emptyData = new FormData();
808
+ break;
809
+ case "stream":
810
+ emptyData = response.body;
811
+ break;
812
+ case "json":
813
+ default:
814
+ emptyData = {};
815
+ break;
816
+ }
817
+ return opts.responseStyle === "data" ? emptyData : {
818
+ data: emptyData,
819
+ ...result
820
+ };
821
+ }
822
+ let data;
823
+ switch (parseAs) {
824
+ case "arrayBuffer":
825
+ case "blob":
826
+ case "formData":
827
+ case "text":
828
+ data = await response[parseAs]();
829
+ break;
830
+ case "json": {
831
+ const text = await response.text();
832
+ data = text ? JSON.parse(text) : {};
833
+ break;
834
+ }
835
+ case "stream":
836
+ return opts.responseStyle === "data" ? response.body : {
837
+ data: response.body,
838
+ ...result
839
+ };
840
+ }
841
+ if (parseAs === "json") {
842
+ if (opts.responseValidator) {
843
+ await opts.responseValidator(data);
844
+ }
845
+ if (opts.responseTransformer) {
846
+ data = await opts.responseTransformer(data);
847
+ }
848
+ }
849
+ return opts.responseStyle === "data" ? data : {
850
+ data,
851
+ ...result
852
+ };
853
+ }
854
+ const textError = await response.text();
855
+ let jsonError;
856
+ try {
857
+ jsonError = JSON.parse(textError);
858
+ } catch {
859
+ }
860
+ throw jsonError ?? textError;
861
+ } catch (error) {
862
+ let finalError = error;
863
+ for (const fn of interceptors.error.fns) {
864
+ if (fn) {
865
+ finalError = await fn(finalError, response, request2, options);
866
+ }
867
+ }
868
+ finalError = finalError || {};
869
+ if (throwOnError) {
870
+ throw finalError;
871
+ }
872
+ return responseStyle === "data" ? void 0 : {
873
+ error: finalError,
874
+ request: request2,
875
+ response
876
+ };
877
+ }
878
+ };
879
+ const makeMethodFn = (method) => (options) => request({ ...options, method });
880
+ const makeSseFn = (method) => async (options) => {
881
+ const { opts, url } = await beforeRequest(options);
882
+ return createSseClient({
883
+ ...opts,
884
+ body: opts.body,
885
+ method,
886
+ onRequest: async (url2, init) => {
887
+ let request2 = new Request(url2, init);
888
+ for (const fn of interceptors.request.fns) {
889
+ if (fn) {
890
+ request2 = await fn(request2, opts);
891
+ }
892
+ }
893
+ return request2;
894
+ },
895
+ serializedBody: getValidRequestBody(opts),
896
+ url
897
+ });
898
+ };
899
+ const _buildUrl = (options) => buildUrl({ ..._config, ...options });
900
+ return {
901
+ buildUrl: _buildUrl,
902
+ connect: makeMethodFn("CONNECT"),
903
+ delete: makeMethodFn("DELETE"),
904
+ get: makeMethodFn("GET"),
905
+ getConfig,
906
+ head: makeMethodFn("HEAD"),
907
+ interceptors,
908
+ options: makeMethodFn("OPTIONS"),
909
+ patch: makeMethodFn("PATCH"),
910
+ post: makeMethodFn("POST"),
911
+ put: makeMethodFn("PUT"),
912
+ request,
913
+ setConfig,
914
+ sse: {
915
+ connect: makeSseFn("CONNECT"),
916
+ delete: makeSseFn("DELETE"),
917
+ get: makeSseFn("GET"),
918
+ head: makeSseFn("HEAD"),
919
+ options: makeSseFn("OPTIONS"),
920
+ patch: makeSseFn("PATCH"),
921
+ post: makeSseFn("POST"),
922
+ put: makeSseFn("PUT"),
923
+ trace: makeSseFn("TRACE")
924
+ },
925
+ trace: makeMethodFn("TRACE")
926
+ };
927
+ };
928
+
929
+ // src/lib/generated/repo-api-client/core/params.gen.ts
930
+ var extraPrefixesMap = {
931
+ $body_: "body",
932
+ $headers_: "headers",
933
+ $path_: "path",
934
+ $query_: "query"
935
+ };
936
+ var extraPrefixes = Object.entries(extraPrefixesMap);
937
+
938
+ // src/lib/generated/repo-api-client/client.gen.ts
939
+ var client = createClient(createConfig());
940
+
941
+ // src/lib/generated/repo-api-client/sdk.gen.ts
942
+ var listRepos = (options) => (options?.client ?? client).get({
943
+ security: [{ scheme: "bearer", type: "http" }],
944
+ url: "/api/v1/repos",
945
+ ...options
946
+ });
947
+ var createRepo = (options) => (options.client ?? client).post({
948
+ security: [{ scheme: "bearer", type: "http" }],
949
+ url: "/api/v1/repos",
950
+ ...options,
951
+ headers: {
952
+ "Content-Type": "application/json",
953
+ ...options.headers
954
+ }
955
+ });
956
+ var deleteRepo = (options) => (options.client ?? client).delete({
957
+ security: [{ scheme: "bearer", type: "http" }],
958
+ url: "/api/v1/repos/{repo_id}",
959
+ ...options
960
+ });
961
+ var createGitToken = (options) => (options.client ?? client).post({
962
+ security: [{ scheme: "bearer", type: "http" }],
963
+ url: "/api/v1/repos/{repo_id}/git-token",
964
+ ...options,
965
+ headers: {
966
+ "Content-Type": "application/json",
967
+ ...options.headers
968
+ }
969
+ });
970
+
971
+ // src/main.ts
972
+ var defaultGitHost = "git.corigin.dev";
973
+ var CliError = class extends Error {
974
+ code;
975
+ constructor(code, message) {
976
+ super(message);
977
+ this.code = code;
978
+ }
979
+ };
980
+ function formatJsonSuccess(command, data) {
981
+ return `${JSON.stringify({ ok: true, command, data })}
982
+ `;
983
+ }
984
+ function formatJsonError(command, code, message) {
985
+ return `${JSON.stringify({ ok: false, command, error: { code, message } })}
986
+ `;
987
+ }
988
+ function redactSecrets(text, secrets) {
989
+ return secrets.reduce(
990
+ (current, secret) => secret ? current.split(secret).join("[redacted]") : current,
991
+ text
992
+ );
993
+ }
994
+ async function writeCredential(configDir, profileName, credential) {
995
+ await writeProfileCredential(configDir, profileName, credential.credential);
996
+ }
997
+ async function readCredential(configDir, profileName) {
998
+ const credential = await readProfileCredential(configDir, profileName);
999
+ return credential === void 0 ? void 0 : { credential: credential.credential };
1000
+ }
1001
+ function parseGitCredentialInput(input) {
1002
+ const fields = Object.fromEntries(
1003
+ input.split(/\r?\n/).filter((line) => line.length > 0).map((line) => {
1004
+ const separator = line.indexOf("=");
1005
+ if (separator < 1)
1006
+ throw new CliError("invalid_git_credential_input", "Git credential input is malformed.");
1007
+ return [line.slice(0, separator), line.slice(separator + 1)];
1008
+ })
1009
+ );
1010
+ if (fields.protocol !== "https")
1011
+ throw new CliError("invalid_git_credential_input", "Git credential protocol must be https.");
1012
+ if (!fields.host)
1013
+ throw new CliError("invalid_git_credential_input", "Git credential host is required.");
1014
+ if (!fields.path)
1015
+ throw new CliError("invalid_git_credential_input", "Git credential path is required.");
1016
+ return { protocol: fields.protocol, host: fields.host, path: fields.path };
1017
+ }
1018
+ function resolveGitCredentialRepo(input) {
1019
+ const normalizedPath = input.path.replace(/^\/+/, "").replace(/\.git$/, "");
1020
+ const parts = normalizedPath.split("/");
1021
+ if (parts.length !== 4 || parts[0] !== "w" || parts[2] !== "r" || !parts[1] || !parts[3]) {
1022
+ throw new CliError(
1023
+ "invalid_git_credential_path",
1024
+ "Git credential path must identify a Corigin repository."
1025
+ );
1026
+ }
1027
+ return { workspaceId: parts[1], repoId: parts[3] };
1028
+ }
1029
+ function createCoriginProgram(deps = {}) {
1030
+ const program = addCliGlobalOptions(
1031
+ new Command().name("corigin").description("Corigin command-line interface").version("0.1.0")
1032
+ );
1033
+ if (deps.exitOverride !== false) program.exitOverride();
1034
+ addCliGlobalOptions(program.command("login")).option("--no-open", "Print the verification URL without opening a browser").option(
1035
+ "--timeout-ms <milliseconds>",
1036
+ "Local login timeout in milliseconds",
1037
+ parsePositiveInteger,
1038
+ 12e4
1039
+ ).action(
1040
+ async (options, command) => runCommand("login", command, deps, () => login(command, options, deps))
1041
+ );
1042
+ const repos = program.command("repos").description("Create, list, and delete hosted repos");
1043
+ addCliGlobalOptions(repos.command("list")).action(
1044
+ async (_options, command) => runCommand("repos list", command, deps, () => reposList(command, deps))
1045
+ );
1046
+ addCliGlobalOptions(repos.command("create")).requiredOption("--name <name>", "Name for the hosted repository").action(
1047
+ async (options, command) => runCommand("repos create", command, deps, () => reposCreate(command, options, deps))
1048
+ );
1049
+ addCliGlobalOptions(repos.command("delete")).requiredOption("--repo <repo-id>", "Repository id to delete").requiredOption("--yes", "Confirm deletion without an interactive prompt").action(
1050
+ async (options, command) => runCommand("repos delete", command, deps, () => reposDelete(command, options, deps))
1051
+ );
1052
+ const gitToken = program.command("git-token").description("Mint scoped Git credentials for a repo");
1053
+ addCliGlobalOptions(gitToken.command("create")).requiredOption("--repo <repo-id>", "Repository id for the Git token").requiredOption("--actor-subject <label>", "Runtime or sandbox actor label").requiredOption("--access <read|write>", "Git operation scope", parseGitAccess).option("--ttl-seconds <seconds>", "Requested token lifetime in seconds", parsePositiveInteger).action(
1054
+ async (options, command) => runCommand("git-token create", command, deps, () => gitTokenCreate(command, options, deps))
1055
+ );
1056
+ const gitCredentials = program.command("git-credentials").description("Install and inspect the Git credential helper");
1057
+ addCliGlobalOptions(gitCredentials.command("install")).option("--git-host <host>", "Git remote host for credential-helper config", defaultGitHost).option("--scope <global|local>", "Git config scope", "global").option("--force", "Replace existing Corigin credential-helper config").action(
1058
+ async (options, command) => runCommand(
1059
+ "git-credentials install",
1060
+ command,
1061
+ deps,
1062
+ async () => gitCredentialsInstall(options)
1063
+ )
1064
+ );
1065
+ addCliGlobalOptions(gitCredentials.command("status")).option("--git-host <host>", "Git remote host for credential-helper config", defaultGitHost).option("--scope <global|local>", "Git config scope", "global").action(
1066
+ async (options, command) => runCommand(
1067
+ "git-credentials status",
1068
+ command,
1069
+ deps,
1070
+ async () => gitCredentialsStatus(options)
1071
+ )
1072
+ );
1073
+ addCliGlobalOptions(gitCredentials.command("uninstall")).option("--git-host <host>", "Git remote host for credential-helper config", defaultGitHost).option("--scope <global|local>", "Git config scope", "global").action(
1074
+ async (options, command) => runCommand(
1075
+ "git-credentials uninstall",
1076
+ command,
1077
+ deps,
1078
+ async () => gitCredentialsUninstall(options)
1079
+ )
1080
+ );
1081
+ addCliGlobalOptions(
1082
+ program.command("git-credential-helper <operation>", { hidden: true })
1083
+ ).action(
1084
+ async (operation, _options, command) => runCommand(
1085
+ "git-credential-helper",
1086
+ command,
1087
+ deps,
1088
+ () => gitCredentialHelper(command, operation, deps)
1089
+ )
1090
+ );
1091
+ return program;
1092
+ }
1093
+ function addCliGlobalOptions(command) {
1094
+ return command.option("--json", "Emit one JSON object on stdout").option("--profile <name>", "Select the local CLI profile for this command").option("--config-dir <path>", "Directory containing config.toml and credentials.toml");
1095
+ }
1096
+ async function runCommand(commandName, command, deps, action) {
1097
+ const commandOptions = command.optsWithGlobals();
1098
+ const stdout = deps.stdout ?? process.stdout;
1099
+ const stderr = deps.stderr ?? process.stderr;
1100
+ await action().then((data) => {
1101
+ if (commandName === "git-credential-helper") return;
1102
+ if (data === void 0) {
1103
+ throw new CliError("command_failed", "Corigin command did not return output data.");
1104
+ }
1105
+ stdout.write(
1106
+ commandOptions.json ? formatJsonSuccess(commandName, data) : formatHumanSuccess(commandName, data)
1107
+ );
1108
+ }).catch((error) => {
1109
+ const cliError = error instanceof CliError ? error : new CliError("command_failed", "Corigin command failed.");
1110
+ if (commandName === "git-credential-helper") {
1111
+ stderr.write(`${cliError.message}
1112
+ `);
1113
+ } else if (commandOptions.json) {
1114
+ stdout.write(formatJsonError(commandName, cliError.code, cliError.message));
1115
+ } else {
1116
+ stderr.write(`${cliError.code}: ${cliError.message}
1117
+ `);
1118
+ }
1119
+ process.exitCode = 1;
1120
+ });
1121
+ }
1122
+ async function login(command, options, deps) {
1123
+ const rootOptions = await rootCliOptions(command, { allowMissingProfile: true });
1124
+ const startResponse = await authFetch(
1125
+ rootOptions.webUrl,
1126
+ "/api/auth/device/code",
1127
+ { client_id: "corigin-cli" },
1128
+ deps.fetch
1129
+ );
1130
+ const verificationUrl = requireString(startResponse, "verification_uri_complete");
1131
+ const userCode = requireString(startResponse, "user_code");
1132
+ const deviceCode = requireString(startResponse, "device_code");
1133
+ let intervalMs = Math.max(1, Number(startResponse.interval ?? 1) * 1e3);
1134
+ const deadline = Date.now() + options.timeoutMs;
1135
+ let forceVerificationOutput = options.open === false;
1136
+ if (options.open !== false) {
1137
+ await (deps.openBrowser ?? openBrowser)(verificationUrl).catch(async () => {
1138
+ forceVerificationOutput = true;
1139
+ await progress(command, deps, "Could not open the browser automatically.", { force: true });
1140
+ });
1141
+ }
1142
+ await progress(command, deps, `Open ${verificationUrl} and enter code ${userCode}.`, {
1143
+ force: forceVerificationOutput
1144
+ });
1145
+ while (Date.now() < deadline) {
1146
+ const pollResponse = await authFetch(
1147
+ rootOptions.webUrl,
1148
+ "/api/auth/device/token",
1149
+ {
1150
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
1151
+ device_code: deviceCode,
1152
+ client_id: "corigin-cli"
1153
+ },
1154
+ deps.fetch
1155
+ );
1156
+ if ("access_token" in pollResponse) {
1157
+ const accessToken = requireString(pollResponse, "access_token");
1158
+ const apiKeyResponse = await authFetch(
1159
+ rootOptions.webUrl,
1160
+ "/api/v1/api-keys",
1161
+ { name: "Corigin CLI" },
1162
+ deps.fetch,
1163
+ { authorization: `Bearer ${accessToken}` }
1164
+ );
1165
+ const apiKey = requireObject(apiKeyResponse, "apiKey");
1166
+ const workspaceId = requireString(apiKey, "workspaceId");
1167
+ const workspaceName = optionalString(apiKeyResponse, "workspaceName") ?? optionalString(apiKey, "workspaceName") ?? workspaceId;
1168
+ await writeConfig(
1169
+ rootOptions.configDir,
1170
+ setProfileConfig(await readConfig(rootOptions.configDir), rootOptions.profileName, {
1171
+ api_url: rootOptions.apiUrl,
1172
+ web_url: rootOptions.webUrl
1173
+ })
1174
+ );
1175
+ await writeCredential(rootOptions.configDir, rootOptions.profileName, {
1176
+ credential: requireString(apiKeyResponse, "secret")
1177
+ });
1178
+ return { workspace_id: workspaceId, workspace_name: workspaceName };
1179
+ }
1180
+ const status = requireString(pollResponse, "status");
1181
+ if (status === "access_denied" || status === "authorization_denied" || status === "denied") {
1182
+ throw new CliError("authorization_denied", "Device authorization was denied.");
1183
+ }
1184
+ if (status === "expired_token" || status === "authorization_expired" || status === "expired") {
1185
+ throw new CliError("authorization_expired", "Device authorization expired.");
1186
+ }
1187
+ if (status === "slow_down")
1188
+ intervalMs = Math.max(intervalMs, Number(pollResponse.interval ?? intervalMs / 1e3) * 1e3);
1189
+ else if (status !== "authorization_pending") {
1190
+ throw new CliError(
1191
+ "provider_error",
1192
+ "Device authorization provider returned an unsupported status."
1193
+ );
1194
+ }
1195
+ await (deps.sleep ?? sleep)(intervalMs);
1196
+ }
1197
+ throw new CliError("authorization_timeout", "Device authorization timed out.");
1198
+ }
1199
+ async function reposList(command, deps) {
1200
+ const { credential, client: client2 } = await authenticatedRepoClient(command, deps);
1201
+ return apiData("repos list", credential, await listRepos({ client: client2 }));
1202
+ }
1203
+ async function reposCreate(command, options, deps) {
1204
+ const { credential, client: client2 } = await authenticatedRepoClient(command, deps);
1205
+ return apiData(
1206
+ "repos create",
1207
+ credential,
1208
+ await createRepo({ client: client2, body: { name: options.name } })
1209
+ );
1210
+ }
1211
+ async function reposDelete(command, options, deps) {
1212
+ const { credential, client: client2 } = await authenticatedRepoClient(command, deps);
1213
+ return apiData(
1214
+ "repos delete",
1215
+ credential,
1216
+ await deleteRepo({ client: client2, path: { repo_id: options.repo } })
1217
+ );
1218
+ }
1219
+ async function gitTokenCreate(command, options, deps) {
1220
+ const { credential, client: client2 } = await authenticatedRepoClient(command, deps);
1221
+ return apiData(
1222
+ "git-token create",
1223
+ credential,
1224
+ await createGitToken({
1225
+ client: client2,
1226
+ path: { repo_id: options.repo },
1227
+ body: {
1228
+ actor_subject: options.actorSubject,
1229
+ access: options.access,
1230
+ ttl_seconds: options.ttlSeconds
1231
+ }
1232
+ })
1233
+ );
1234
+ }
1235
+ async function gitCredentialHelper(command, operation, deps) {
1236
+ if (!["get", "store", "erase"].includes(operation))
1237
+ throw new CliError("invalid_git_credential_operation", "Git helper operation is unsupported.");
1238
+ const stdin = await readStdin(deps.stdin ?? process.stdin);
1239
+ if (operation !== "get") return;
1240
+ const parsed = parseGitCredentialInput(stdin);
1241
+ const { repoId } = resolveGitCredentialRepo(parsed);
1242
+ const rootOptions = await rootCliOptions(command);
1243
+ const credential = await requireCredential(rootOptions.configDir, rootOptions.profileName);
1244
+ const client2 = repoClient(rootOptions.apiUrl, credential.credential, deps.fetch);
1245
+ const response = await apiData(
1246
+ "git-credential-helper",
1247
+ credential,
1248
+ await createGitToken({
1249
+ client: client2,
1250
+ path: { repo_id: repoId },
1251
+ body: { actor_subject: "corigin git-credential-helper", access: "write" }
1252
+ })
1253
+ );
1254
+ const token = objectData(response) === null ? "" : stringField(objectData(response), "token");
1255
+ if (!token) throw new CliError("repo_api_error", "Repo API did not return a Git token.");
1256
+ (deps.stdout ?? process.stdout).write(`username=agent
1257
+ password=${token}
1258
+
1259
+ `);
1260
+ }
1261
+ function gitCredentialsInstall(options) {
1262
+ assertGitScope(options.scope);
1263
+ const helperKey = `credential.https://${options.gitHost}.helper`;
1264
+ const useHttpPathKey = `credential.https://${options.gitHost}.useHttpPath`;
1265
+ if (!options.force && (gitConfigGet(options.scope, helperKey) || gitConfigGet(options.scope, useHttpPathKey))) {
1266
+ throw new CliError(
1267
+ "git_credentials_already_configured",
1268
+ "Corigin Git credential helper config already exists; rerun with --force to replace it."
1269
+ );
1270
+ }
1271
+ gitConfigUnset(options.scope, helperKey);
1272
+ gitConfigAdd(options.scope, [helperKey, ""]);
1273
+ gitConfigAdd(options.scope, [helperKey, "!corigin git-credential-helper"]);
1274
+ gitConfig(options.scope, [useHttpPathKey, "true"]);
1275
+ return { git_host: options.gitHost, installed: true };
1276
+ }
1277
+ function gitCredentialsStatus(options) {
1278
+ assertGitScope(options.scope);
1279
+ const helpers = gitConfigGetAll(options.scope, `credential.https://${options.gitHost}.helper`);
1280
+ const useHttpPath = gitConfigGet(
1281
+ options.scope,
1282
+ `credential.https://${options.gitHost}.useHttpPath`
1283
+ );
1284
+ return {
1285
+ git_host: options.gitHost,
1286
+ installed: helpers.includes("") && helpers.includes("!corigin git-credential-helper") && useHttpPath === "true"
1287
+ };
1288
+ }
1289
+ function gitCredentialsUninstall(options) {
1290
+ assertGitScope(options.scope);
1291
+ gitConfigUnset(options.scope, `credential.https://${options.gitHost}.helper`);
1292
+ gitConfigUnset(options.scope, `credential.https://${options.gitHost}.useHttpPath`);
1293
+ return { git_host: options.gitHost, installed: false };
1294
+ }
1295
+ async function authenticatedRepoClient(command, deps) {
1296
+ const options = await rootCliOptions(command);
1297
+ const credential = await requireCredential(options.configDir, options.profileName);
1298
+ return { credential, client: repoClient(options.apiUrl, credential.credential, deps.fetch) };
1299
+ }
1300
+ function repoClient(apiUrl, credential, fetchImpl) {
1301
+ return createClient({ baseUrl: apiUrl, auth: credential, fetch: fetchImpl });
1302
+ }
1303
+ async function apiData(command, credential, result) {
1304
+ if (result.error) {
1305
+ const errorCode = stringField(objectData(result.error), "code");
1306
+ if (result.response?.status === 401 || errorCode === "workspace_api_key_invalid") {
1307
+ throw new CliError("not_logged_in", "Run corigin login before using this command.");
1308
+ }
1309
+ const message = stringField(objectData(result.error), "message") || "Repo API request failed.";
1310
+ throw new CliError("repo_api_error", redactSecrets(message, [credential.credential]));
1311
+ }
1312
+ if (result.data === void 0) {
1313
+ throw new CliError("repo_api_error", "Repo API response did not include data.");
1314
+ }
1315
+ return result.data;
1316
+ }
1317
+ async function requireCredential(configDir, profileName) {
1318
+ const credential = await readCredential(configDir, profileName);
1319
+ if (credential) return credential;
1320
+ if (profileName === "default") {
1321
+ const migrated = await migrateLegacyCredential(configDir).catch((error) => {
1322
+ if (error.message === "Legacy credentials are ambiguous. Run corigin login --profile <name>.") {
1323
+ throw new CliError("legacy_credentials_ambiguous", error.message);
1324
+ }
1325
+ throw error;
1326
+ });
1327
+ if (migrated !== void 0) {
1328
+ await writeCredential(configDir, profileName, migrated);
1329
+ return migrated;
1330
+ }
1331
+ }
1332
+ throw new CliError("not_logged_in", "Run corigin login before using this command.");
1333
+ }
1334
+ async function authFetch(webUrl, route, body, fetchImpl = fetch, headers = {}) {
1335
+ const response = await fetchImpl(new URL(route, webUrl), {
1336
+ method: "POST",
1337
+ headers: { ...headers, "content-type": "application/json" },
1338
+ body: JSON.stringify(body)
1339
+ });
1340
+ const parsed = z3.record(z3.string(), z3.json()).parse(await response.json());
1341
+ if (!response.ok) {
1342
+ if (typeof parsed.error === "string") {
1343
+ return { status: parsed.error, message: parsed.error_description };
1344
+ }
1345
+ throw new CliError(
1346
+ stringField(parsed, "code") || "authorization_failed",
1347
+ stringField(parsed, "message") || "Device authorization failed."
1348
+ );
1349
+ }
1350
+ return parsed;
1351
+ }
1352
+ async function rootCliOptions(command, profileOptions = {}) {
1353
+ const commandOptions = command.optsWithGlobals();
1354
+ const configDir = commandOptions.configDir ?? defaultConfigDir;
1355
+ const config = await readConfig(configDir);
1356
+ const profileName = resolveProfileName(config, commandOptions.profile);
1357
+ const profileConfig = profileOptions.allowMissingProfile && config.profiles?.[profileName] === void 0 ? defaultProfileConfig : config.profiles?.[profileName] ?? (profileName === "default" ? defaultProfileConfig : new CliError(
1358
+ "profile_not_configured",
1359
+ `Profile '${profileName}' is not configured. Run corigin login --profile ${profileName}.`
1360
+ ));
1361
+ if (profileConfig instanceof CliError) {
1362
+ throw new CliError("profile_not_configured", profileConfig.message);
1363
+ }
1364
+ return {
1365
+ configDir,
1366
+ profileName,
1367
+ apiUrl: profileConfig.api_url,
1368
+ webUrl: profileConfig.web_url,
1369
+ json: commandOptions.json
1370
+ };
1371
+ }
1372
+ function formatHumanSuccess(command, data) {
1373
+ const value = objectData(data);
1374
+ if (command === "repos list" && Array.isArray(value?.repos)) {
1375
+ if (value.repos.length === 0) return "No repos found.\n";
1376
+ return `${value.repos.map((repo) => {
1377
+ const repoValue = objectData(repo);
1378
+ return `${stringField(repoValue, "name")} ${stringField(repoValue, "repo_id")} ${stringField(repoValue, "git_url")}`;
1379
+ }).join("\n")}
1380
+ `;
1381
+ }
1382
+ if (command === "repos create" && value && "repo" in value) {
1383
+ const repo = objectData(value.repo);
1384
+ return `Created repo ${stringField(repo, "name")}.
1385
+ Repo ID: ${stringField(repo, "repo_id")}
1386
+ Git URL: ${stringField(repo, "git_url")}
1387
+ `;
1388
+ }
1389
+ if (command === "repos delete" && value && "repo" in value) {
1390
+ const repo = objectData(value.repo);
1391
+ return `Deleted repo ${stringField(repo, "name")}.
1392
+ Repo ID: ${stringField(repo, "repo_id")}
1393
+ `;
1394
+ }
1395
+ if (command === "git-token create" && value) {
1396
+ return `Git URL: ${stringField(value, "git_url")}
1397
+ Token: ${stringField(value, "token")}
1398
+ `;
1399
+ }
1400
+ if (command === "git-credentials install") {
1401
+ return "Corigin Git credential helper installed.\n";
1402
+ }
1403
+ if (command === "git-credentials status" && value && "installed" in value) {
1404
+ return value.installed ? "Corigin Git credential helper is installed.\n" : "Corigin Git credential helper is not installed.\n";
1405
+ }
1406
+ if (command === "git-credentials uninstall") {
1407
+ return "Corigin Git credential helper uninstalled.\n";
1408
+ }
1409
+ if (command === "login" && value && "workspace_name" in value) {
1410
+ return `Logged in to ${stringField(value, "workspace_name")}.
1411
+ `;
1412
+ }
1413
+ return "Done.\n";
1414
+ }
1415
+ function objectData(value) {
1416
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1417
+ return null;
1418
+ }
1419
+ const objectValue = value;
1420
+ return objectValue;
1421
+ }
1422
+ function stringField(value, key) {
1423
+ const field = value?.[key];
1424
+ return typeof field === "string" ? field : "";
1425
+ }
1426
+ function requireString(value, key) {
1427
+ const result = value[key];
1428
+ if (typeof result !== "string" || result.length === 0)
1429
+ throw new CliError("invalid_response", `Device authorization response is missing ${key}.`);
1430
+ return result;
1431
+ }
1432
+ function requireObject(value, key) {
1433
+ const result = value[key];
1434
+ if (!result || typeof result !== "object" || Array.isArray(result)) {
1435
+ throw new CliError("invalid_response", `Device authorization response is missing ${key}.`);
1436
+ }
1437
+ const objectResult = result;
1438
+ return objectResult;
1439
+ }
1440
+ function optionalString(value, key) {
1441
+ const result = value[key];
1442
+ return typeof result === "string" && result.length > 0 ? result : null;
1443
+ }
1444
+ async function progress(command, deps, message, options = {}) {
1445
+ const commandOptions = command.optsWithGlobals();
1446
+ const stderr = deps.stderr ?? process.stderr;
1447
+ if (options.force || commandOptions.json || stderrIsTty(stderr)) stderr.write(`${message}
1448
+ `);
1449
+ }
1450
+ function stderrIsTty(stderr) {
1451
+ return "isTTY" in stderr && stderr.isTTY === true;
1452
+ }
1453
+ function parsePositiveInteger(value) {
1454
+ const parsed = z3.coerce.number().int().positive().safeParse(value);
1455
+ if (!parsed.success) {
1456
+ throw new InvalidArgumentError("must be a positive integer");
1457
+ }
1458
+ return parsed.data;
1459
+ }
1460
+ function parseGitAccess(value) {
1461
+ if (value !== "read" && value !== "write")
1462
+ throw new InvalidArgumentError("must be read or write");
1463
+ return value;
1464
+ }
1465
+ function assertGitScope(scope) {
1466
+ if (scope !== "global" && scope !== "local")
1467
+ throw new CliError("invalid_git_config_scope", "Git config scope must be global or local.");
1468
+ }
1469
+ function gitConfig(scope, args) {
1470
+ const result = spawnSync("git", ["config", `--${scope}`, ...args], { encoding: "utf8" });
1471
+ if (result.status !== 0)
1472
+ throw new CliError("git_config_failed", "Git credential-helper config failed.");
1473
+ }
1474
+ function gitConfigAdd(scope, args) {
1475
+ const result = spawnSync("git", ["config", `--${scope}`, "--add", ...args], {
1476
+ encoding: "utf8"
1477
+ });
1478
+ if (result.status !== 0)
1479
+ throw new CliError("git_config_failed", "Git credential-helper config failed.");
1480
+ }
1481
+ function gitConfigGet(scope, key) {
1482
+ const result = spawnSync("git", ["config", `--${scope}`, "--get", key], { encoding: "utf8" });
1483
+ return result.status === 0 ? result.stdout.trim() : void 0;
1484
+ }
1485
+ function gitConfigGetAll(scope, key) {
1486
+ const result = spawnSync("git", ["config", `--${scope}`, "--get-all", key], {
1487
+ encoding: "utf8"
1488
+ });
1489
+ return result.status === 0 ? result.stdout.split(/\r?\n/).slice(0, -1) : [];
1490
+ }
1491
+ function gitConfigUnset(scope, key) {
1492
+ spawnSync("git", ["config", `--${scope}`, "--unset-all", key], { encoding: "utf8" });
1493
+ }
1494
+ function sleep(milliseconds) {
1495
+ return new Promise((resolve) => setTimeout(resolve, milliseconds));
1496
+ }
1497
+ async function openBrowser(url) {
1498
+ const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
1499
+ const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
1500
+ const result = spawnSync(command, args, { stdio: "ignore" });
1501
+ if (result.error || result.status !== null && result.status !== 0) {
1502
+ throw new CliError(
1503
+ "browser_open_failed",
1504
+ "Could not open the browser."
1505
+ );
1506
+ }
1507
+ }
1508
+ function readStdin(stdin) {
1509
+ return new Promise((resolve, reject) => {
1510
+ let result = "";
1511
+ stdin.setEncoding("utf8");
1512
+ stdin.on("data", (chunk) => {
1513
+ result += chunk;
1514
+ });
1515
+ stdin.on("error", reject);
1516
+ stdin.on("end", () => resolve(result));
1517
+ });
1518
+ }
1519
+ async function runCli(argv = process.argv, deps = {}) {
1520
+ await createCoriginProgram(deps).parseAsync(argv);
1521
+ }
1522
+ if (isCliEntrypoint()) {
1523
+ runCli().catch((error) => {
1524
+ const exitCode = error instanceof CommanderError ? commanderExitCode(error) : 1;
1525
+ if (exitCode !== 0 && !(error instanceof CommanderError)) {
1526
+ process.stderr.write(
1527
+ `${error instanceof Error ? error.message : "Corigin command failed."}
1528
+ `
1529
+ );
1530
+ }
1531
+ process.exitCode = exitCode;
1532
+ });
1533
+ }
1534
+ function isCliEntrypoint() {
1535
+ const invokedPath = process.argv[1];
1536
+ return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(invokedPath);
1537
+ }
1538
+ function commanderExitCode(error) {
1539
+ return error.code.startsWith("commander.") && error.exitCode !== 0 ? 2 : error.exitCode;
1540
+ }
1541
+ export {
1542
+ createCoriginProgram,
1543
+ formatJsonError,
1544
+ formatJsonSuccess,
1545
+ parseGitCredentialInput,
1546
+ readCredential,
1547
+ redactSecrets,
1548
+ resolveGitCredentialRepo,
1549
+ runCli,
1550
+ writeCredential
1551
+ };