@guaracloud/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 (160) hide show
  1. package/bin/dev.js +4 -0
  2. package/bin/run.js +4 -0
  3. package/dist/commands/config/get.d.ts +10 -0
  4. package/dist/commands/config/get.d.ts.map +1 -0
  5. package/dist/commands/config/get.js +21 -0
  6. package/dist/commands/config/get.js.map +1 -0
  7. package/dist/commands/config/list.d.ts +7 -0
  8. package/dist/commands/config/list.d.ts.map +1 -0
  9. package/dist/commands/config/list.js +31 -0
  10. package/dist/commands/config/list.js.map +1 -0
  11. package/dist/commands/config/reset.d.ts +7 -0
  12. package/dist/commands/config/reset.d.ts.map +1 -0
  13. package/dist/commands/config/reset.js +25 -0
  14. package/dist/commands/config/reset.js.map +1 -0
  15. package/dist/commands/config/set.d.ts +11 -0
  16. package/dist/commands/config/set.d.ts.map +1 -0
  17. package/dist/commands/config/set.js +29 -0
  18. package/dist/commands/config/set.js.map +1 -0
  19. package/dist/commands/deploy.d.ts +25 -0
  20. package/dist/commands/deploy.d.ts.map +1 -0
  21. package/dist/commands/deploy.js +115 -0
  22. package/dist/commands/deploy.js.map +1 -0
  23. package/dist/commands/deployments/list.d.ts +7 -0
  24. package/dist/commands/deployments/list.d.ts.map +1 -0
  25. package/dist/commands/deployments/list.js +40 -0
  26. package/dist/commands/deployments/list.js.map +1 -0
  27. package/dist/commands/domains/add.d.ts +17 -0
  28. package/dist/commands/domains/add.d.ts.map +1 -0
  29. package/dist/commands/domains/add.js +41 -0
  30. package/dist/commands/domains/add.js.map +1 -0
  31. package/dist/commands/domains/list.d.ts +7 -0
  32. package/dist/commands/domains/list.d.ts.map +1 -0
  33. package/dist/commands/domains/list.js +32 -0
  34. package/dist/commands/domains/list.js.map +1 -0
  35. package/dist/commands/domains/remove.d.ts +17 -0
  36. package/dist/commands/domains/remove.d.ts.map +1 -0
  37. package/dist/commands/domains/remove.js +60 -0
  38. package/dist/commands/domains/remove.js.map +1 -0
  39. package/dist/commands/env/list.d.ts +7 -0
  40. package/dist/commands/env/list.d.ts.map +1 -0
  41. package/dist/commands/env/list.js +32 -0
  42. package/dist/commands/env/list.js.map +1 -0
  43. package/dist/commands/env/set.d.ts +18 -0
  44. package/dist/commands/env/set.d.ts.map +1 -0
  45. package/dist/commands/env/set.js +70 -0
  46. package/dist/commands/env/set.js.map +1 -0
  47. package/dist/commands/env/unset.d.ts +8 -0
  48. package/dist/commands/env/unset.d.ts.map +1 -0
  49. package/dist/commands/env/unset.js +36 -0
  50. package/dist/commands/env/unset.js.map +1 -0
  51. package/dist/commands/link.d.ts +16 -0
  52. package/dist/commands/link.d.ts.map +1 -0
  53. package/dist/commands/link.js +123 -0
  54. package/dist/commands/link.js.map +1 -0
  55. package/dist/commands/login.d.ts +28 -0
  56. package/dist/commands/login.d.ts.map +1 -0
  57. package/dist/commands/login.js +190 -0
  58. package/dist/commands/login.js.map +1 -0
  59. package/dist/commands/logout.d.ts +7 -0
  60. package/dist/commands/logout.d.ts.map +1 -0
  61. package/dist/commands/logout.js +33 -0
  62. package/dist/commands/logout.js.map +1 -0
  63. package/dist/commands/logs.d.ts +24 -0
  64. package/dist/commands/logs.d.ts.map +1 -0
  65. package/dist/commands/logs.js +174 -0
  66. package/dist/commands/logs.js.map +1 -0
  67. package/dist/commands/open.d.ts +17 -0
  68. package/dist/commands/open.d.ts.map +1 -0
  69. package/dist/commands/open.js +78 -0
  70. package/dist/commands/open.js.map +1 -0
  71. package/dist/commands/projects/create.d.ts +19 -0
  72. package/dist/commands/projects/create.d.ts.map +1 -0
  73. package/dist/commands/projects/create.js +79 -0
  74. package/dist/commands/projects/create.js.map +1 -0
  75. package/dist/commands/projects/info.d.ts +7 -0
  76. package/dist/commands/projects/info.d.ts.map +1 -0
  77. package/dist/commands/projects/info.js +39 -0
  78. package/dist/commands/projects/info.js.map +1 -0
  79. package/dist/commands/projects/list.d.ts +7 -0
  80. package/dist/commands/projects/list.d.ts.map +1 -0
  81. package/dist/commands/projects/list.js +38 -0
  82. package/dist/commands/projects/list.js.map +1 -0
  83. package/dist/commands/rollback.d.ts +17 -0
  84. package/dist/commands/rollback.d.ts.map +1 -0
  85. package/dist/commands/rollback.js +63 -0
  86. package/dist/commands/rollback.js.map +1 -0
  87. package/dist/commands/scale.d.ts +18 -0
  88. package/dist/commands/scale.d.ts.map +1 -0
  89. package/dist/commands/scale.js +96 -0
  90. package/dist/commands/scale.js.map +1 -0
  91. package/dist/commands/services/create.d.ts +23 -0
  92. package/dist/commands/services/create.d.ts.map +1 -0
  93. package/dist/commands/services/create.js +146 -0
  94. package/dist/commands/services/create.js.map +1 -0
  95. package/dist/commands/services/delete.d.ts +7 -0
  96. package/dist/commands/services/delete.d.ts.map +1 -0
  97. package/dist/commands/services/delete.js +41 -0
  98. package/dist/commands/services/delete.js.map +1 -0
  99. package/dist/commands/services/info.d.ts +7 -0
  100. package/dist/commands/services/info.d.ts.map +1 -0
  101. package/dist/commands/services/info.js +46 -0
  102. package/dist/commands/services/info.js.map +1 -0
  103. package/dist/commands/services/list.d.ts +7 -0
  104. package/dist/commands/services/list.d.ts.map +1 -0
  105. package/dist/commands/services/list.js +40 -0
  106. package/dist/commands/services/list.js.map +1 -0
  107. package/dist/commands/services/restart.d.ts +7 -0
  108. package/dist/commands/services/restart.d.ts.map +1 -0
  109. package/dist/commands/services/restart.js +27 -0
  110. package/dist/commands/services/restart.js.map +1 -0
  111. package/dist/commands/services/start.d.ts +7 -0
  112. package/dist/commands/services/start.d.ts.map +1 -0
  113. package/dist/commands/services/start.js +27 -0
  114. package/dist/commands/services/start.js.map +1 -0
  115. package/dist/commands/services/stop.d.ts +7 -0
  116. package/dist/commands/services/stop.d.ts.map +1 -0
  117. package/dist/commands/services/stop.js +27 -0
  118. package/dist/commands/services/stop.js.map +1 -0
  119. package/dist/commands/status.d.ts +11 -0
  120. package/dist/commands/status.d.ts.map +1 -0
  121. package/dist/commands/status.js +87 -0
  122. package/dist/commands/status.js.map +1 -0
  123. package/dist/commands/unlink.d.ts +7 -0
  124. package/dist/commands/unlink.d.ts.map +1 -0
  125. package/dist/commands/unlink.js +43 -0
  126. package/dist/commands/unlink.js.map +1 -0
  127. package/dist/commands/whoami.d.ts +7 -0
  128. package/dist/commands/whoami.d.ts.map +1 -0
  129. package/dist/commands/whoami.js +46 -0
  130. package/dist/commands/whoami.js.map +1 -0
  131. package/dist/index.d.ts +2 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +2 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/lib/api-client.d.ts +96 -0
  136. package/dist/lib/api-client.d.ts.map +1 -0
  137. package/dist/lib/api-client.js +256 -0
  138. package/dist/lib/api-client.js.map +1 -0
  139. package/dist/lib/auth.d.ts +68 -0
  140. package/dist/lib/auth.d.ts.map +1 -0
  141. package/dist/lib/auth.js +180 -0
  142. package/dist/lib/auth.js.map +1 -0
  143. package/dist/lib/base-command.d.ts +94 -0
  144. package/dist/lib/base-command.d.ts.map +1 -0
  145. package/dist/lib/base-command.js +184 -0
  146. package/dist/lib/base-command.js.map +1 -0
  147. package/dist/lib/context.d.ts +58 -0
  148. package/dist/lib/context.d.ts.map +1 -0
  149. package/dist/lib/context.js +147 -0
  150. package/dist/lib/context.js.map +1 -0
  151. package/dist/lib/errors.d.ts +34 -0
  152. package/dist/lib/errors.d.ts.map +1 -0
  153. package/dist/lib/errors.js +143 -0
  154. package/dist/lib/errors.js.map +1 -0
  155. package/dist/lib/output.d.ts +19 -0
  156. package/dist/lib/output.d.ts.map +1 -0
  157. package/dist/lib/output.js +75 -0
  158. package/dist/lib/output.js.map +1 -0
  159. package/oclif.manifest.json +2880 -0
  160. package/package.json +92 -0
@@ -0,0 +1,184 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import chalk from 'chalk';
3
+ import { ApiError, GuaraApiClient } from './api-client.js';
4
+ import { getApiKey, getApiUrl } from './auth.js';
5
+ import { resolveContext } from './context.js';
6
+ import { CliError, formatApiError, getExitCode } from './errors.js';
7
+ import { errorMessage, formatJson, formatQuiet } from './output.js';
8
+ // ─── Global flag definitions ──────────────────────────────────────────────
9
+ export const globalFlags = {
10
+ json: Flags.boolean({
11
+ description: 'Output as JSON.',
12
+ default: false,
13
+ }),
14
+ quiet: Flags.boolean({
15
+ char: 'q',
16
+ description: 'Suppress all non-essential output.',
17
+ default: false,
18
+ }),
19
+ 'api-key': Flags.string({
20
+ description: 'Override the API key for this request.',
21
+ env: 'GUARA_API_KEY',
22
+ helpGroup: 'GLOBAL',
23
+ }),
24
+ 'api-url': Flags.string({
25
+ description: 'Override the API base URL.',
26
+ env: 'GUARA_API_URL',
27
+ helpGroup: 'GLOBAL',
28
+ }),
29
+ project: Flags.string({
30
+ char: 'p',
31
+ description: 'Project slug (overrides .guara.json and $GUARA_PROJECT).',
32
+ env: 'GUARA_PROJECT',
33
+ helpGroup: 'GLOBAL',
34
+ }),
35
+ service: Flags.string({
36
+ char: 's',
37
+ description: 'Service slug (overrides .guara.json and $GUARA_SERVICE).',
38
+ env: 'GUARA_SERVICE',
39
+ helpGroup: 'GLOBAL',
40
+ }),
41
+ yes: Flags.boolean({
42
+ char: 'y',
43
+ description: 'Skip confirmation prompts.',
44
+ default: false,
45
+ }),
46
+ };
47
+ // ─── Abstract base command ────────────────────────────────────────────────
48
+ /**
49
+ * Abstract base class for all GuaraCloud CLI commands.
50
+ *
51
+ * Provides:
52
+ * - Global flags (json, quiet, api-key, api-url, project, service, yes)
53
+ * - API client initialisation via {@link initApiClient}
54
+ * - Context resolution via {@link resolveContext}
55
+ * - Helper methods for project/service requirement enforcement
56
+ * - Structured JSON and quiet output helpers
57
+ * - Unified error handling for ApiError, CliError, and unexpected errors
58
+ */
59
+ export class BaseCommand extends Command {
60
+ static baseFlags = globalFlags;
61
+ // ─── API client ────────────────────────────────────────────────────────
62
+ /**
63
+ * Create an authenticated {@link GuaraApiClient} using the resolved flags.
64
+ *
65
+ * Resolution order for the API key:
66
+ * 1. `--api-key` flag
67
+ * 2. Auth module (env -> keychain -> config file)
68
+ *
69
+ * Resolution order for the API URL:
70
+ * 1. `--api-url` flag
71
+ * 2. Auth module (env -> config file, defaults to https://api.guaracloud.com)
72
+ */
73
+ async initApiClient(flags) {
74
+ const apiKey = flags['api-key'] ?? (await getApiKey());
75
+ const baseUrl = flags['api-url'] ?? getApiUrl();
76
+ return GuaraApiClient.create({ apiKey, baseUrl });
77
+ }
78
+ // ─── Context resolution ────────────────────────────────────────────────
79
+ /**
80
+ * Resolve project/service context from flags, environment, or `.guara.json`.
81
+ *
82
+ * Returns `undefined` when no project could be determined from any source.
83
+ */
84
+ async resolveProjectContext(flags) {
85
+ return resolveContext({
86
+ project: flags.project,
87
+ service: flags.service,
88
+ });
89
+ }
90
+ /**
91
+ * Resolve context and fail if no project is available.
92
+ * Resolves slug to UUID via the API client when needed.
93
+ *
94
+ * @returns The resolved project UUID.
95
+ * @throws {CliError} when no project could be resolved.
96
+ */
97
+ async requireProject(flags, client) {
98
+ const ctx = await this.resolveProjectContext(flags);
99
+ if (!ctx) {
100
+ throw new CliError('No project specified.', 1, 'Pass --project <slug>, set $GUARA_PROJECT, or run `guara link` in a project directory.');
101
+ }
102
+ return client.resolveProjectId(ctx.project);
103
+ }
104
+ /**
105
+ * Resolve context and fail if no service is available.
106
+ * Resolves slugs to UUIDs via the API client when needed.
107
+ *
108
+ * @returns A tuple of `[projectId, serviceId]` (UUIDs).
109
+ * @throws {CliError} when project or service could not be resolved.
110
+ */
111
+ async requireService(flags, client) {
112
+ const ctx = await this.resolveProjectContext(flags);
113
+ if (!ctx) {
114
+ throw new CliError('No project specified.', 1, 'Pass --project <slug>, set $GUARA_PROJECT, or run `guara link` in a project directory.');
115
+ }
116
+ if (!ctx.service) {
117
+ throw new CliError('No service specified.', 1, 'Pass --service <slug>, set $GUARA_SERVICE, or include "service" in .guara.json.');
118
+ }
119
+ const projectId = await client.resolveProjectId(ctx.project);
120
+ const serviceId = await client.resolveServiceId(projectId, ctx.service);
121
+ return [projectId, serviceId];
122
+ }
123
+ // ─── Output helpers ────────────────────────────────────────────────────
124
+ /**
125
+ * Print structured JSON to stdout and return it (so oclif's `--json`
126
+ * envelope can use the value if `enableJsonFlag` is set on the command).
127
+ */
128
+ outputJson(data) {
129
+ this.log(formatJson(data));
130
+ }
131
+ /**
132
+ * Print a minimal value for `--quiet` mode (e.g. a slug or ID).
133
+ */
134
+ outputQuiet(value) {
135
+ this.log(formatQuiet(value));
136
+ }
137
+ // ─── Error handling ────────────────────────────────────────────────────
138
+ /**
139
+ * Unified error handler that formats known error types into user-friendly
140
+ * messages, with optional JSON output.
141
+ */
142
+ // eslint-disable-next-line @typescript-eslint/require-await
143
+ async catch(err) {
144
+ // ── ApiError from the HTTP client ──────────────────────────────────
145
+ if (err instanceof ApiError) {
146
+ const isJson = this.argv.includes('--json');
147
+ const formatted = formatApiError({
148
+ statusCode: err.statusCode,
149
+ error: err.name,
150
+ message: err.message,
151
+ errorCode: err.errorCode,
152
+ details: err.details,
153
+ requestId: err.requestId,
154
+ }, isJson);
155
+ if (isJson && formatted.json) {
156
+ this.logToStderr(JSON.stringify(formatted.json, null, 2));
157
+ }
158
+ else {
159
+ this.logToStderr(errorMessage(formatted.message));
160
+ if (formatted.suggestion) {
161
+ this.logToStderr(chalk.dim(` Hint: ${formatted.suggestion}`));
162
+ }
163
+ }
164
+ this.exit(getExitCode(err.statusCode));
165
+ }
166
+ // ── CliError (AuthenticationError, NetworkError, etc.) ─────────────
167
+ if (err instanceof CliError) {
168
+ const isJson = this.argv.includes('--json');
169
+ if (isJson) {
170
+ this.logToStderr(JSON.stringify({ error: { code: err.name, message: err.message } }, null, 2));
171
+ }
172
+ else {
173
+ this.logToStderr(errorMessage(err.message));
174
+ if (err.suggestion) {
175
+ this.logToStderr(chalk.dim(` Hint: ${err.suggestion}`));
176
+ }
177
+ }
178
+ this.exit(err.exitCode);
179
+ }
180
+ // ── Fallback: delegate to oclif's default handler ─────────────────
181
+ throw err;
182
+ }
183
+ }
184
+ //# sourceMappingURL=base-command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-command.js","sourceRoot":"","sources":["../../src/lib/base-command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import { z } from 'zod';
2
+ declare const guaraLinkSchema: z.ZodObject<{
3
+ project: z.ZodString;
4
+ service: z.ZodOptional<z.ZodString>;
5
+ }, z.core.$strip>;
6
+ export type GuaraLink = z.infer<typeof guaraLinkSchema>;
7
+ export interface ResolvedContext {
8
+ /** Project slug (always present when context is resolved). */
9
+ project: string;
10
+ /** Service slug (optional — present when service is linked or passed via flag). */
11
+ service: string | undefined;
12
+ /** Source of the project value for diagnostics. */
13
+ projectSource: 'flag' | 'env' | 'link-file';
14
+ /** Source of the service value for diagnostics. */
15
+ serviceSource: 'flag' | 'env' | 'link-file' | 'none';
16
+ }
17
+ interface ContextInputs {
18
+ /** `--project` flag value. */
19
+ project?: string;
20
+ /** `--service` flag value. */
21
+ service?: string;
22
+ /** Working directory to search for .guara.json (defaults to cwd). */
23
+ cwd?: string;
24
+ }
25
+ /**
26
+ * Resolve project and service context from flags, environment, or link file.
27
+ *
28
+ * Resolution order for **project**:
29
+ * 1. `--project` flag
30
+ * 2. `GUARA_PROJECT` environment variable
31
+ * 3. `.guara.json` link file (walked upward from cwd)
32
+ *
33
+ * Resolution order for **service**:
34
+ * 1. `--service` flag
35
+ * 2. `GUARA_SERVICE` environment variable
36
+ * 3. `.guara.json` link file `service` field (if present)
37
+ *
38
+ * Returns `undefined` if no project could be resolved.
39
+ */
40
+ export declare function resolveContext(inputs?: ContextInputs): Promise<ResolvedContext | undefined>;
41
+ /**
42
+ * Write a `.guara.json` link file in the given directory.
43
+ */
44
+ export declare function writeLinkFile(dir: string, link: GuaraLink): Promise<string>;
45
+ /**
46
+ * Remove the `.guara.json` link file from the given directory.
47
+ *
48
+ * Returns `true` if the file was deleted, `false` if it did not exist.
49
+ */
50
+ export declare function removeLinkFile(dir: string): Promise<boolean>;
51
+ /**
52
+ * Read and validate a `.guara.json` link file from the given directory.
53
+ *
54
+ * Returns `undefined` if the file doesn't exist or is invalid.
55
+ */
56
+ export declare function readLinkFile(dir: string): Promise<GuaraLink | undefined>;
57
+ export {};
58
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/lib/context.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,QAAA,MAAM,eAAe;;;iBAGnB,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAIxD,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,mDAAmD;IACnD,aAAa,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;IAC5C,mDAAmD;IACnD,aAAa,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,GAAG,MAAM,CAAC;CACtD;AAID,UAAU,aAAa;IACrB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA4CD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,cAAc,CAClC,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAiDtC;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAKjF;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUlE;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAiB9E"}
@@ -0,0 +1,147 @@
1
+ import { readFile, writeFile, unlink, access, constants } from 'node:fs/promises';
2
+ import { resolve, dirname } from 'node:path';
3
+ import { z } from 'zod';
4
+ // ─── Zod schema for .guara.json ────────────────────────────────────────────
5
+ const guaraLinkSchema = z.object({
6
+ project: z.string().min(1, 'project slug is required'),
7
+ service: z.string().min(1, 'service slug is required').optional(),
8
+ });
9
+ // ─── Link file I/O ─────────────────────────────────────────────────────────
10
+ const LINK_FILENAME = '.guara.json';
11
+ /**
12
+ * Walk from `startDir` upward to the filesystem root, looking for `.guara.json`.
13
+ * Returns the parsed link data or `undefined` if not found.
14
+ */
15
+ async function findLinkFile(startDir) {
16
+ let dir = resolve(startDir);
17
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
18
+ while (true) {
19
+ const candidate = resolve(dir, LINK_FILENAME);
20
+ try {
21
+ await access(candidate, constants.R_OK);
22
+ const raw = await readFile(candidate, 'utf-8');
23
+ const parsed = JSON.parse(raw);
24
+ const result = guaraLinkSchema.safeParse(parsed);
25
+ if (result.success) {
26
+ return result.data;
27
+ }
28
+ // File exists but is invalid — stop searching upward.
29
+ return undefined;
30
+ }
31
+ catch {
32
+ // File doesn't exist or isn't readable — walk up.
33
+ }
34
+ const parent = dirname(dir);
35
+ if (parent === dir) {
36
+ // Reached filesystem root.
37
+ break;
38
+ }
39
+ dir = parent;
40
+ }
41
+ return undefined;
42
+ }
43
+ /**
44
+ * Resolve project and service context from flags, environment, or link file.
45
+ *
46
+ * Resolution order for **project**:
47
+ * 1. `--project` flag
48
+ * 2. `GUARA_PROJECT` environment variable
49
+ * 3. `.guara.json` link file (walked upward from cwd)
50
+ *
51
+ * Resolution order for **service**:
52
+ * 1. `--service` flag
53
+ * 2. `GUARA_SERVICE` environment variable
54
+ * 3. `.guara.json` link file `service` field (if present)
55
+ *
56
+ * Returns `undefined` if no project could be resolved.
57
+ */
58
+ export async function resolveContext(inputs = {}) {
59
+ const cwd = inputs.cwd ?? process.cwd();
60
+ // ── Project resolution ──────────────────────────────────────────────
61
+ let project;
62
+ let projectSource = 'link-file';
63
+ if (inputs.project) {
64
+ project = inputs.project;
65
+ projectSource = 'flag';
66
+ }
67
+ else if (process.env['GUARA_PROJECT']) {
68
+ project = process.env['GUARA_PROJECT'];
69
+ projectSource = 'env';
70
+ }
71
+ // ── Service resolution ──────────────────────────────────────────────
72
+ let service;
73
+ let serviceSource = 'none';
74
+ if (inputs.service) {
75
+ service = inputs.service;
76
+ serviceSource = 'flag';
77
+ }
78
+ else if (process.env['GUARA_SERVICE']) {
79
+ service = process.env['GUARA_SERVICE'];
80
+ serviceSource = 'env';
81
+ }
82
+ // ── Link file fallback ──────────────────────────────────────────────
83
+ if (!project || (!service && serviceSource === 'none')) {
84
+ const link = await findLinkFile(cwd);
85
+ if (link) {
86
+ if (!project) {
87
+ project = link.project;
88
+ projectSource = 'link-file';
89
+ }
90
+ if (!service && link.service) {
91
+ service = link.service;
92
+ serviceSource = 'link-file';
93
+ }
94
+ }
95
+ }
96
+ if (!project) {
97
+ return undefined;
98
+ }
99
+ return { project, service, projectSource, serviceSource };
100
+ }
101
+ /**
102
+ * Write a `.guara.json` link file in the given directory.
103
+ */
104
+ export async function writeLinkFile(dir, link) {
105
+ const filePath = resolve(dir, LINK_FILENAME);
106
+ const content = JSON.stringify(link, null, 2) + '\n';
107
+ await writeFile(filePath, content, 'utf-8');
108
+ return filePath;
109
+ }
110
+ /**
111
+ * Remove the `.guara.json` link file from the given directory.
112
+ *
113
+ * Returns `true` if the file was deleted, `false` if it did not exist.
114
+ */
115
+ export async function removeLinkFile(dir) {
116
+ const filePath = resolve(dir, LINK_FILENAME);
117
+ try {
118
+ await access(filePath, constants.R_OK);
119
+ await unlink(filePath);
120
+ return true;
121
+ }
122
+ catch {
123
+ return false;
124
+ }
125
+ }
126
+ /**
127
+ * Read and validate a `.guara.json` link file from the given directory.
128
+ *
129
+ * Returns `undefined` if the file doesn't exist or is invalid.
130
+ */
131
+ export async function readLinkFile(dir) {
132
+ const filePath = resolve(dir, LINK_FILENAME);
133
+ try {
134
+ await access(filePath, constants.R_OK);
135
+ const raw = await readFile(filePath, 'utf-8');
136
+ const parsed = JSON.parse(raw);
137
+ const result = guaraLinkSchema.safeParse(parsed);
138
+ if (result.success) {
139
+ return result.data;
140
+ }
141
+ return undefined;
142
+ }
143
+ catch {
144
+ return undefined;
145
+ }
146
+ }
147
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/lib/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export interface ApiErrorBody {
2
+ statusCode: number;
3
+ error: string;
4
+ message: string;
5
+ errorCode?: string;
6
+ details?: Record<string, unknown>;
7
+ requestId?: string;
8
+ }
9
+ interface FormattedError {
10
+ message: string;
11
+ suggestion: string;
12
+ json?: {
13
+ error: {
14
+ code: string;
15
+ message: string;
16
+ status: number;
17
+ };
18
+ };
19
+ }
20
+ export declare function formatApiError(body: ApiErrorBody, json?: boolean): FormattedError;
21
+ export declare function getExitCode(statusCode: number): number;
22
+ export declare class CliError extends Error {
23
+ readonly exitCode: number;
24
+ readonly suggestion?: string;
25
+ constructor(message: string, exitCode?: number, suggestion?: string);
26
+ }
27
+ export declare class AuthenticationError extends CliError {
28
+ constructor(message?: string);
29
+ }
30
+ export declare class NetworkError extends CliError {
31
+ constructor(apiUrl: string);
32
+ }
33
+ export {};
34
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACrE;AAoGD,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,UAAQ,GAAG,cAAc,CA0B/E;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,QAAQ,EAAE,MAAM,CAAC;IACjC,SAAgB,UAAU,CAAC,EAAE,MAAM,CAAC;gBAExB,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAI,EAAE,UAAU,CAAC,EAAE,MAAM;CAM/D;AAED,qBAAa,mBAAoB,SAAQ,QAAQ;gBACnC,OAAO,SAAgD;CAGpE;AAED,qBAAa,YAAa,SAAQ,QAAQ;gBAC5B,MAAM,EAAE,MAAM;CAO3B"}
@@ -0,0 +1,143 @@
1
+ const ERROR_MAP = {
2
+ CONCURRENT_BUILD: {
3
+ message: 'A build is already in progress.',
4
+ suggestion: 'Run `guara deployments list` to check current status.',
5
+ },
6
+ TIER_LIMIT_EXCEEDED: {
7
+ message: 'Resource exceeds your tier quota.',
8
+ suggestion: 'Upgrade your tier at app.guaracloud.com or reduce resources.',
9
+ },
10
+ BUILD_QUOTA_EXCEEDED: {
11
+ message: 'Build minutes quota exceeded.',
12
+ suggestion: 'Upgrade your tier or wait for the next billing cycle.',
13
+ },
14
+ RESOURCE_POOL_EXCEEDED: {
15
+ message: 'Account resource pool exhausted.',
16
+ suggestion: 'Scale down other services or upgrade your tier.',
17
+ },
18
+ PROJECT_LIMIT_EXCEEDED: {
19
+ message: 'Maximum number of projects reached for your tier.',
20
+ suggestion: 'Delete an unused project or upgrade your tier.',
21
+ },
22
+ SERVICE_LIMIT_EXCEEDED: {
23
+ message: 'Maximum number of services reached for this project.',
24
+ suggestion: 'Delete an unused service or upgrade your tier.',
25
+ },
26
+ DOMAIN_LIMIT_EXCEEDED: {
27
+ message: 'Maximum number of custom domains reached.',
28
+ suggestion: 'Remove an existing domain or upgrade your tier.',
29
+ },
30
+ API_KEY_LIMIT_EXCEEDED: {
31
+ message: 'Maximum number of API keys reached for your tier.',
32
+ suggestion: 'Revoke an unused key at app.guaracloud.com or upgrade your tier.',
33
+ },
34
+ INVALID_API_KEY: {
35
+ message: 'Authentication failed. API key is invalid or revoked.',
36
+ suggestion: 'Run `guara login` to re-authenticate.',
37
+ },
38
+ API_KEY_EXPIRED: {
39
+ message: 'Authentication failed. API key has expired.',
40
+ suggestion: 'Run `guara login` to generate a new key.',
41
+ },
42
+ API_KEY_SCOPE_INSUFFICIENT: {
43
+ message: 'Your API key lacks the required permission scope.',
44
+ suggestion: 'Create a new key with write scope at app.guaracloud.com.',
45
+ },
46
+ ACCOUNT_SUSPENDED: {
47
+ message: 'Account is suspended due to billing issues.',
48
+ suggestion: 'Update payment method at app.guaracloud.com.',
49
+ },
50
+ RATE_LIMITED: {
51
+ message: 'Too many requests. Rate limit exceeded.',
52
+ suggestion: 'Wait a moment and try again.',
53
+ },
54
+ PROJECT_NOT_FOUND: {
55
+ message: 'Project not found or you do not have access.',
56
+ suggestion: 'Check project slug with `guara projects list`.',
57
+ },
58
+ SERVICE_NOT_FOUND: {
59
+ message: 'Service not found or you do not have access.',
60
+ suggestion: 'Check service slug with `guara services list`.',
61
+ },
62
+ DEPLOYMENT_NOT_FOUND: {
63
+ message: 'Deployment not found.',
64
+ suggestion: 'Check deployment history with `guara deployments list`.',
65
+ },
66
+ PAYMENT_FAILED: {
67
+ message: 'Payment failed.',
68
+ suggestion: 'Update your payment method at app.guaracloud.com.',
69
+ },
70
+ TOS_NOT_ACCEPTED: {
71
+ message: 'Terms of Service and Privacy Policy must be accepted before using the CLI.',
72
+ suggestion: 'Accept the Terms of Service at https://app.guaracloud.com and try again.',
73
+ },
74
+ ACCOUNT_DELETION_PENDING: {
75
+ message: 'Account is scheduled for deletion.',
76
+ suggestion: 'Cancel deletion at https://app.guaracloud.com if this was unintentional.',
77
+ },
78
+ };
79
+ const STATUS_FALLBACKS = {
80
+ 401: {
81
+ message: 'Authentication failed.',
82
+ suggestion: 'Run `guara login` to re-authenticate.',
83
+ },
84
+ 403: {
85
+ message: 'You do not have permission for this action.',
86
+ suggestion: 'Check your role with `guara whoami` or contact the project owner.',
87
+ },
88
+ 404: {
89
+ message: 'Resource not found.',
90
+ suggestion: 'Verify the project and service with `guara projects list`.',
91
+ },
92
+ 429: {
93
+ message: 'Too many requests.',
94
+ suggestion: 'Wait a moment and try again.',
95
+ },
96
+ };
97
+ export function formatApiError(body, json = false) {
98
+ const defaultError = {
99
+ message: 'Something went wrong.',
100
+ suggestion: 'Run with `--json` for details.',
101
+ };
102
+ const byCode = body.errorCode ? ERROR_MAP[body.errorCode] : undefined;
103
+ const byStatus = STATUS_FALLBACKS[body.statusCode];
104
+ const mapped = byCode ?? byStatus ?? defaultError;
105
+ const result = {
106
+ message: mapped.message,
107
+ suggestion: mapped.suggestion,
108
+ };
109
+ if (json) {
110
+ result.json = {
111
+ error: {
112
+ code: body.errorCode ?? 'UNKNOWN_ERROR',
113
+ message: mapped.message,
114
+ status: body.statusCode,
115
+ },
116
+ };
117
+ }
118
+ return result;
119
+ }
120
+ export function getExitCode(statusCode) {
121
+ return statusCode === 401 ? 2 : 1;
122
+ }
123
+ export class CliError extends Error {
124
+ exitCode;
125
+ suggestion;
126
+ constructor(message, exitCode = 1, suggestion) {
127
+ super(message);
128
+ this.name = 'CliError';
129
+ this.exitCode = exitCode;
130
+ this.suggestion = suggestion;
131
+ }
132
+ }
133
+ export class AuthenticationError extends CliError {
134
+ constructor(message = 'Not authenticated. Run `guara login` first.') {
135
+ super(message, 2, 'Run `guara login` to authenticate.');
136
+ }
137
+ }
138
+ export class NetworkError extends CliError {
139
+ constructor(apiUrl) {
140
+ super(`Could not reach GuaraCloud API at ${apiUrl}.`, 1, 'Check your internet connection and API URL (`guara config get api-url`).');
141
+ }
142
+ }
143
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ interface PaginationMeta {
2
+ page: number;
3
+ limit: number;
4
+ total: number;
5
+ total_pages: number;
6
+ has_next: boolean;
7
+ has_previous: boolean;
8
+ }
9
+ export declare function formatJson(data: unknown, meta?: PaginationMeta): string;
10
+ export declare function formatQuiet(value: string | string[]): string;
11
+ export declare function formatTable(headers: string[], rows: string[][]): string;
12
+ export declare function colorizeLogLevel(level: string): string;
13
+ export declare function formatLogLine(timestamp: string, level: string, message: string): string;
14
+ export declare function statusColor(status: string): string;
15
+ export declare function successMessage(text: string): string;
16
+ export declare function errorMessage(text: string): string;
17
+ export declare function infoBlock(title: string, fields: Array<[string, string]>): string;
18
+ export {};
19
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAGA,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,MAAM,CAGvE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,CAE5D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CASvE;AAWD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAIvF;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA0BlD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,CAIhF"}