@guildai/cli 0.11.0 → 0.12.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 (198) hide show
  1. package/dist/auth-CRMO5O3N.js +29 -0
  2. package/dist/auth-CRMO5O3N.js.map +7 -0
  3. package/dist/chat-5VX2WJH2.js +303 -0
  4. package/dist/chat-5VX2WJH2.js.map +7 -0
  5. package/dist/chat-SIKDYZQK.js +31 -0
  6. package/dist/chat-SIKDYZQK.js.map +7 -0
  7. package/dist/chunk-56YCMGL3.js +522 -0
  8. package/dist/chunk-56YCMGL3.js.map +7 -0
  9. package/dist/chunk-6EX6E7WP.js +7042 -0
  10. package/dist/chunk-6EX6E7WP.js.map +7 -0
  11. package/dist/chunk-B7VAF5UG.js +532 -0
  12. package/dist/chunk-B7VAF5UG.js.map +7 -0
  13. package/dist/chunk-DOIYVBNY.js +3057 -0
  14. package/dist/chunk-DOIYVBNY.js.map +7 -0
  15. package/dist/chunk-ENKEEJ45.js +17 -0
  16. package/dist/chunk-ENKEEJ45.js.map +7 -0
  17. package/dist/chunk-IBRKVGMZ.js +97041 -0
  18. package/dist/chunk-IBRKVGMZ.js.map +7 -0
  19. package/dist/chunk-LFMQJOKC.js +19778 -0
  20. package/dist/chunk-LFMQJOKC.js.map +7 -0
  21. package/dist/chunk-M347HP6M.js +22896 -0
  22. package/dist/chunk-M347HP6M.js.map +7 -0
  23. package/dist/chunk-OYQ476FQ.js +44 -0
  24. package/dist/chunk-OYQ476FQ.js.map +7 -0
  25. package/dist/chunk-PNCUR4OB.js +257 -0
  26. package/dist/chunk-PNCUR4OB.js.map +7 -0
  27. package/dist/chunk-RIG2HZWM.js +317 -0
  28. package/dist/chunk-RIG2HZWM.js.map +7 -0
  29. package/dist/chunk-SPZPZXUN.js +826 -0
  30. package/dist/chunk-SPZPZXUN.js.map +7 -0
  31. package/dist/chunk-VVSOU6ON.js +53 -0
  32. package/dist/chunk-VVSOU6ON.js.map +7 -0
  33. package/dist/chunk-X3ADGWOF.js +3643 -0
  34. package/dist/chunk-X3ADGWOF.js.map +7 -0
  35. package/dist/commands/skill/create.d.ts +3 -0
  36. package/dist/commands/skill/get.d.ts +3 -0
  37. package/dist/commands/skill/list.d.ts +3 -0
  38. package/dist/commands/skill/update.d.ts +3 -0
  39. package/dist/commands/skill/version/create.d.ts +3 -0
  40. package/dist/commands/skill/version/get.d.ts +3 -0
  41. package/dist/commands/skill/version/list.d.ts +3 -0
  42. package/dist/devtools-AO7YSDOD.js +67 -0
  43. package/dist/devtools-AO7YSDOD.js.map +7 -0
  44. package/dist/dist-4CBK6X5H.js +1566 -0
  45. package/dist/dist-4CBK6X5H.js.map +7 -0
  46. package/dist/esm-FRAVZP4J.js +13 -0
  47. package/dist/esm-FRAVZP4J.js.map +7 -0
  48. package/dist/execa-XQMWSABC.js +35 -0
  49. package/dist/execa-XQMWSABC.js.map +7 -0
  50. package/dist/index.js +8230 -263
  51. package/dist/index.js.map +7 -0
  52. package/dist/lib/api-types.d.ts +44 -0
  53. package/dist/lib/config.d.ts +9 -0
  54. package/dist/lib/errors.d.ts +1 -1
  55. package/dist/lib/output.d.ts +11 -1
  56. package/dist/lib/session-events.d.ts +1 -1
  57. package/dist/lib/session-polling.d.ts +24 -1
  58. package/dist/lib/websocket-client.d.ts +46 -0
  59. package/dist/open-RF4X5MOP.js +13 -0
  60. package/dist/open-RF4X5MOP.js.map +7 -0
  61. package/dist/server-JYVH64FD.js +27659 -0
  62. package/dist/server-JYVH64FD.js.map +7 -0
  63. package/dist/test-SNIYRJ32.js +692 -0
  64. package/dist/test-SNIYRJ32.js.map +7 -0
  65. package/docs/skills/codex-agent-dev.md +2 -2
  66. package/package.json +8 -12
  67. package/dist/commands/agent/chat.js +0 -281
  68. package/dist/commands/agent/clone.js +0 -118
  69. package/dist/commands/agent/code.js +0 -87
  70. package/dist/commands/agent/fork.js +0 -220
  71. package/dist/commands/agent/get.js +0 -37
  72. package/dist/commands/agent/grep.js +0 -107
  73. package/dist/commands/agent/init.js +0 -403
  74. package/dist/commands/agent/list.js +0 -110
  75. package/dist/commands/agent/logs.js +0 -62
  76. package/dist/commands/agent/owners.js +0 -74
  77. package/dist/commands/agent/publish.js +0 -91
  78. package/dist/commands/agent/pull.js +0 -194
  79. package/dist/commands/agent/revalidate.js +0 -56
  80. package/dist/commands/agent/save.js +0 -345
  81. package/dist/commands/agent/search.js +0 -61
  82. package/dist/commands/agent/tags/add.js +0 -73
  83. package/dist/commands/agent/tags/list.js +0 -43
  84. package/dist/commands/agent/tags/remove.js +0 -84
  85. package/dist/commands/agent/tags/set.js +0 -71
  86. package/dist/commands/agent/test.js +0 -489
  87. package/dist/commands/agent/unpublish.js +0 -64
  88. package/dist/commands/agent/update.js +0 -118
  89. package/dist/commands/agent/versions.js +0 -55
  90. package/dist/commands/agent/workspaces.js +0 -54
  91. package/dist/commands/auth/login.js +0 -31
  92. package/dist/commands/auth/logout.js +0 -24
  93. package/dist/commands/auth/status.js +0 -38
  94. package/dist/commands/auth/token.js +0 -19
  95. package/dist/commands/chat.js +0 -1416
  96. package/dist/commands/config/get.js +0 -64
  97. package/dist/commands/config/list.js +0 -46
  98. package/dist/commands/config/path.js +0 -37
  99. package/dist/commands/config/set.js +0 -132
  100. package/dist/commands/credentials/endpoint-list.js +0 -88
  101. package/dist/commands/credentials/list.js +0 -50
  102. package/dist/commands/credentials/policy-create.js +0 -66
  103. package/dist/commands/credentials/policy-delete.js +0 -33
  104. package/dist/commands/credentials/policy-list.js +0 -45
  105. package/dist/commands/credentials/policy-update.js +0 -66
  106. package/dist/commands/doctor.js +0 -233
  107. package/dist/commands/integration/connect.js +0 -76
  108. package/dist/commands/integration/create.js +0 -298
  109. package/dist/commands/integration/get.js +0 -95
  110. package/dist/commands/integration/list.js +0 -62
  111. package/dist/commands/integration/operation/create.js +0 -164
  112. package/dist/commands/integration/operation/list.js +0 -92
  113. package/dist/commands/integration/update.js +0 -139
  114. package/dist/commands/integration/version/build.js +0 -86
  115. package/dist/commands/integration/version/create.js +0 -45
  116. package/dist/commands/integration/version/get.js +0 -72
  117. package/dist/commands/integration/version/list.js +0 -45
  118. package/dist/commands/integration/version/publish.js +0 -79
  119. package/dist/commands/integration/version/test.js +0 -104
  120. package/dist/commands/job/get-step.js +0 -40
  121. package/dist/commands/job/get.js +0 -44
  122. package/dist/commands/mcp.js +0 -34
  123. package/dist/commands/session/create.js +0 -59
  124. package/dist/commands/session/events.js +0 -56
  125. package/dist/commands/session/get.js +0 -33
  126. package/dist/commands/session/interrupt.js +0 -33
  127. package/dist/commands/session/list.js +0 -59
  128. package/dist/commands/session/send.js +0 -54
  129. package/dist/commands/session/tasks.js +0 -45
  130. package/dist/commands/setup.js +0 -260
  131. package/dist/commands/trigger/activate.js +0 -41
  132. package/dist/commands/trigger/create.js +0 -197
  133. package/dist/commands/trigger/deactivate.js +0 -41
  134. package/dist/commands/trigger/get.js +0 -33
  135. package/dist/commands/trigger/list.js +0 -57
  136. package/dist/commands/trigger/sessions.js +0 -48
  137. package/dist/commands/trigger/update.js +0 -128
  138. package/dist/commands/version.js +0 -24
  139. package/dist/commands/workspace/agent/add.js +0 -114
  140. package/dist/commands/workspace/agent/list.js +0 -78
  141. package/dist/commands/workspace/agent/remove.js +0 -78
  142. package/dist/commands/workspace/clear.js +0 -45
  143. package/dist/commands/workspace/context/edit.js +0 -107
  144. package/dist/commands/workspace/context/get.js +0 -47
  145. package/dist/commands/workspace/context/list.js +0 -51
  146. package/dist/commands/workspace/context/publish.js +0 -42
  147. package/dist/commands/workspace/create.js +0 -51
  148. package/dist/commands/workspace/current.js +0 -63
  149. package/dist/commands/workspace/get.js +0 -39
  150. package/dist/commands/workspace/list.js +0 -70
  151. package/dist/commands/workspace/select.js +0 -184
  152. package/dist/components/AgentInstallPrompt.js +0 -97
  153. package/dist/components/SplashAnimation.js +0 -321
  154. package/dist/components/TaskView.js +0 -268
  155. package/dist/lib/agent-helpers.js +0 -306
  156. package/dist/lib/alternate-screen.js +0 -59
  157. package/dist/lib/api-client.js +0 -154
  158. package/dist/lib/api-types.js +0 -10
  159. package/dist/lib/auth.js +0 -284
  160. package/dist/lib/braille-canvas.js +0 -321
  161. package/dist/lib/colors.js +0 -46
  162. package/dist/lib/config-cache.js +0 -45
  163. package/dist/lib/config.js +0 -153
  164. package/dist/lib/did-you-mean.js +0 -144
  165. package/dist/lib/errors.js +0 -375
  166. package/dist/lib/event-filter.js +0 -91
  167. package/dist/lib/generated-types.js +0 -56
  168. package/dist/lib/git.js +0 -176
  169. package/dist/lib/gk.js +0 -91
  170. package/dist/lib/guild-config.js +0 -178
  171. package/dist/lib/iap.js +0 -117
  172. package/dist/lib/integration-helpers.js +0 -38
  173. package/dist/lib/loading-messages.js +0 -72
  174. package/dist/lib/logo.js +0 -141
  175. package/dist/lib/lottie-serverside.js +0 -181
  176. package/dist/lib/markdown.js +0 -38
  177. package/dist/lib/npmrc.js +0 -59
  178. package/dist/lib/output-mode.js +0 -54
  179. package/dist/lib/output.js +0 -622
  180. package/dist/lib/owner-helpers.js +0 -112
  181. package/dist/lib/polling.js +0 -76
  182. package/dist/lib/progress.js +0 -324
  183. package/dist/lib/session-events-fetch.js +0 -25
  184. package/dist/lib/session-events.js +0 -126
  185. package/dist/lib/session-polling.js +0 -166
  186. package/dist/lib/session-resume.js +0 -229
  187. package/dist/lib/spinners.js +0 -770
  188. package/dist/lib/splash.js +0 -42
  189. package/dist/lib/stdin.js +0 -91
  190. package/dist/lib/svg-to-braille.js +0 -76
  191. package/dist/lib/table.js +0 -59
  192. package/dist/lib/update-check.js +0 -65
  193. package/dist/lib/validate-input-schema.js +0 -208
  194. package/dist/lib/version-helpers.js +0 -137
  195. package/dist/lib/workspace-helpers.js +0 -49
  196. package/dist/mcp/resources.js +0 -67
  197. package/dist/mcp/server.js +0 -64
  198. package/dist/mcp/tools.js +0 -753
@@ -1,153 +0,0 @@
1
- // Copyright 2026 Guild.ai
2
- // SPDX-License-Identifier: Apache-2.0
3
- import { readFileSync } from 'fs';
4
- import path from 'path';
5
- const FALLBACK_VERSION = 'unknown';
6
- let cachedVersion;
7
- export function getCliVersion() {
8
- if (!cachedVersion) {
9
- try {
10
- const pkg = JSON.parse(readFileSync(path.join(__dirname, '../package.json'), 'utf-8'));
11
- cachedVersion = pkg.version ?? FALLBACK_VERSION;
12
- }
13
- catch {
14
- cachedVersion = FALLBACK_VERSION;
15
- }
16
- }
17
- return cachedVersion;
18
- }
19
- export function isDevBuild() {
20
- try {
21
- return !__dirname.includes('node_modules');
22
- }
23
- catch {
24
- return false;
25
- }
26
- }
27
- export function getUserAgent() {
28
- try {
29
- const base = `GuildCLI/${getCliVersion()}`;
30
- return isDevBuild() ? `${base}/dev` : base;
31
- }
32
- catch {
33
- return 'GuildCLI';
34
- }
35
- }
36
- /**
37
- * IAP configuration for shared.guildai.dev
38
- */
39
- const SHARED_IAP_CONFIG = {
40
- clientId: '468228011370-r08nhcdu6817hv0iol5at6f5t58sjn43.apps.googleusercontent.com',
41
- serviceAccount: 'iap-auth@guildai-infra-shared.iam.gserviceaccount.com',
42
- };
43
- /**
44
- * IAP configuration for mgorven.guildai.dev
45
- */
46
- const MGORVEN_IAP_CONFIG = {
47
- clientId: '1015386688686-7luftqika30hoon0i1tbkl6sbg1qg8fh.apps.googleusercontent.com',
48
- serviceAccount: 'iap-auth@guildai-infra-mgorven.iam.gserviceaccount.com',
49
- };
50
- /**
51
- * Get IAP configuration for the given URL
52
- *
53
- * Returns the appropriate IAP client ID and service account based on the target URL.
54
- *
55
- * @returns IAP config if URL is IAP-protected, null otherwise
56
- */
57
- export function getIapConfig(url) {
58
- try {
59
- const parsed = new URL(url);
60
- if (parsed.hostname === 'shared.guildai.dev') {
61
- return SHARED_IAP_CONFIG;
62
- }
63
- if (parsed.hostname === 'mgorven.guildai.dev') {
64
- return MGORVEN_IAP_CONFIG;
65
- }
66
- }
67
- catch {
68
- // Invalid URL - not IAP protected
69
- }
70
- return null;
71
- }
72
- /**
73
- * @deprecated Use getIapConfig(url).clientId instead
74
- */
75
- export const IAP_CLIENT_ID = SHARED_IAP_CONFIG.clientId;
76
- /**
77
- * @deprecated Use getIapConfig(url).serviceAccount instead
78
- */
79
- export const IAP_SERVICE_ACCOUNT = SHARED_IAP_CONFIG.serviceAccount;
80
- /**
81
- * GuildCore URL constants
82
- */
83
- const PROD_GUILDCORE_URL = 'https://app.guild.ai/api';
84
- const SHARED_GUILDCORE_URL = 'https://shared.guildai.dev/api';
85
- const LOCAL_GUILDCORE_URL = 'http://localhost:5001/api';
86
- /**
87
- * Default GuildCore URL (production)
88
- */
89
- const DEFAULT_GUILDCORE_URL = PROD_GUILDCORE_URL;
90
- /**
91
- * Get the Guildcore API base URL
92
- *
93
- * Returns the base URL for the Guildcore API with /api prefix.
94
- * All public API routes (agents, workspaces, sessions, oauth, me) are under /api.
95
- *
96
- * Priority:
97
- * 1. --shared flag (sets GUILD_USE_SHARED=1)
98
- * 2. --local flag (sets GUILD_USE_LOCAL=1)
99
- * 3. GUILDCORE_URL environment variable (if set)
100
- * 4. GUILDCORE_PORT environment variable (constructs localhost URL)
101
- * 5. Default: https://app.guild.ai/api
102
- *
103
- * @returns Base URL for Guildcore API (e.g., "https://app.guild.ai/api")
104
- */
105
- export function getGuildcoreUrl() {
106
- // Check for --shared flag (undocumented dev shortcut)
107
- if (process.env.GUILD_USE_SHARED === '1') {
108
- return SHARED_GUILDCORE_URL;
109
- }
110
- // Check for --local flag (undocumented dev shortcut)
111
- if (process.env.GUILD_USE_LOCAL === '1') {
112
- return LOCAL_GUILDCORE_URL;
113
- }
114
- // Use explicit URL if provided
115
- if (process.env.GUILDCORE_URL) {
116
- let url = process.env.GUILDCORE_URL.replace(/\/+$/, '');
117
- if (!url.endsWith('/api')) {
118
- url += '/api';
119
- }
120
- return url;
121
- }
122
- // Use localhost if port is explicitly set (for local development)
123
- if (process.env.GUILDCORE_PORT) {
124
- return `http://localhost:${process.env.GUILDCORE_PORT}/api`;
125
- }
126
- // Default to production
127
- return DEFAULT_GUILDCORE_URL;
128
- }
129
- /**
130
- * Get the dashboard (frontend) base URL
131
- *
132
- * Derives the frontend URL from the guildcore API URL by stripping /api.
133
- * Used to construct clickable links to dashboard pages.
134
- */
135
- export function getDashboardUrl() {
136
- return getGuildcoreUrl().replace(/\/api$/, '');
137
- }
138
- /**
139
- * Check if the given URL is an IAP-protected host
140
- *
141
- * IAP-protected hosts:
142
- * - *.guildai.dev (shared, staging environments)
143
- */
144
- export function isIapProtectedUrl(url) {
145
- try {
146
- const parsed = new URL(url);
147
- return parsed.hostname.endsWith('.guildai.dev');
148
- }
149
- catch {
150
- return false;
151
- }
152
- }
153
- //# sourceMappingURL=config.js.map
@@ -1,144 +0,0 @@
1
- // Copyright 2026 Guild.ai
2
- // SPDX-License-Identifier: Apache-2.0
3
- /**
4
- * Recursively collects all commands from the command tree.
5
- * Includes both leaf commands and command groups (parents with subcommands).
6
- * Aliases are added as separate entries.
7
- */
8
- export function getAllCommands(cmd, prefix = '') {
9
- const results = [];
10
- for (const sub of cmd.commands) {
11
- const name = sub.name();
12
- const cmdPath = prefix ? `${prefix} ${name}` : name;
13
- const description = sub.description();
14
- const hasChildren = sub.commands.length > 0;
15
- // Always include this command (even if it has subcommands)
16
- results.push({ path: cmdPath, description, leafName: name });
17
- // If this command has subcommands, also recurse into them
18
- if (hasChildren) {
19
- results.push(...getAllCommands(sub, cmdPath));
20
- }
21
- // Add aliases as separate entries
22
- for (const alias of sub.aliases()) {
23
- const aliasPath = prefix ? `${prefix} ${alias}` : alias;
24
- results.push({ path: aliasPath, description, leafName: alias });
25
- if (hasChildren) {
26
- results.push(...getAllCommands(sub, aliasPath));
27
- }
28
- }
29
- }
30
- return results;
31
- }
32
- /**
33
- * Standard Levenshtein distance between two strings.
34
- */
35
- export function levenshtein(a, b) {
36
- const m = a.length;
37
- const n = b.length;
38
- // Use a single-row DP approach for space efficiency
39
- const row = Array.from({ length: n + 1 }, (_, i) => i);
40
- for (let i = 1; i <= m; i++) {
41
- let prev = i - 1;
42
- row[0] = i;
43
- for (let j = 1; j <= n; j++) {
44
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
45
- const val = Math.min(row[j] + 1, // deletion
46
- row[j - 1] + 1, // insertion
47
- prev + cost // substitution
48
- );
49
- prev = row[j];
50
- row[j] = val;
51
- }
52
- }
53
- return row[n];
54
- }
55
- /**
56
- * Recursively disables Commander's built-in suggestion on all commands.
57
- */
58
- function disableBuiltinSuggestions(cmd) {
59
- cmd.showSuggestionAfterError(false);
60
- for (const sub of cmd.commands) {
61
- disableBuiltinSuggestions(sub);
62
- }
63
- }
64
- /**
65
- * Creates the writeErr handler that intercepts "unknown command" errors
66
- * and prints cross-level suggestions.
67
- */
68
- function createWriteErrHandler(program) {
69
- return (str) => {
70
- // Always write the original error
71
- process.stderr.write(str);
72
- // Check if this is an "unknown command" error
73
- const match = /unknown command '([^']+)'/.exec(str);
74
- if (!match) {
75
- return;
76
- }
77
- const unknown = match[1];
78
- const allCommands = getAllCommands(program);
79
- // Determine the typed parent context from process.argv
80
- // e.g., "guild agent trigger" → typed args are ["agent", "trigger"]
81
- const typedArgs = process.argv.slice(2);
82
- const typedParent = typedArgs.slice(0, -1).join(' ');
83
- // Score each command
84
- const scored = allCommands.map((entry) => {
85
- const leafName = entry.leafName;
86
- // Exact leaf name match gets score 0
87
- let score = leafName === unknown ? 0 : levenshtein(unknown, leafName);
88
- // Context bonus: if command's parent matches typed parent, reduce score
89
- const entryParts = entry.path.split(' ');
90
- const entryParent = entryParts.slice(0, -1).join(' ');
91
- if (entryParent === typedParent && score > 0) {
92
- score -= 0.5;
93
- }
94
- return { ...entry, score };
95
- });
96
- // Filter poor matches
97
- const threshold = Math.max(2, unknown.length / 2);
98
- const filtered = scored.filter((s) => s.score <= threshold);
99
- if (filtered.length === 0) {
100
- return;
101
- }
102
- // Sort by score, deduplicate by path
103
- filtered.sort((a, b) => a.score - b.score);
104
- const seen = new Set();
105
- const unique = filtered.filter((entry) => {
106
- if (seen.has(entry.path)) {
107
- return false;
108
- }
109
- seen.add(entry.path);
110
- return true;
111
- });
112
- // Print top 5 suggestions
113
- const top = unique.slice(0, 5);
114
- process.stderr.write('\nDid you mean?\n');
115
- for (const entry of top) {
116
- const cmd = `guild ${entry.path}`;
117
- const padding = ' '.repeat(Math.max(2, 30 - cmd.length));
118
- process.stderr.write(` ${cmd}${padding}${entry.description}\n`);
119
- }
120
- };
121
- }
122
- /**
123
- * Recursively configures writeErr on a command and all its subcommands.
124
- */
125
- function configureOutputRecursively(cmd, writeErr) {
126
- cmd.configureOutput({ writeErr });
127
- for (const sub of cmd.commands) {
128
- configureOutputRecursively(sub, writeErr);
129
- }
130
- }
131
- /**
132
- * Sets up cross-level "Did you mean?" suggestions for unknown commands.
133
- *
134
- * Disables Commander's built-in same-level suggestions and intercepts
135
- * "unknown command" errors to search the entire command tree.
136
- */
137
- export function setupUnknownCommandSuggestions(program) {
138
- // Disable Commander's built-in suggestion on all commands
139
- disableBuiltinSuggestions(program);
140
- // Create a shared writeErr handler and apply it to all commands
141
- const writeErr = createWriteErrHandler(program);
142
- configureOutputRecursively(program, writeErr);
143
- }
144
- //# sourceMappingURL=did-you-mean.js.map
@@ -1,375 +0,0 @@
1
- // Copyright 2026 Guild.ai
2
- // SPDX-License-Identifier: Apache-2.0
3
- /**
4
- * Standardized error handling utilities for Guild CLI
5
- */
6
- import { getConfigFlag } from './config-cache.js';
7
- export class GuildCLIError extends Error {
8
- code;
9
- details;
10
- constructor(code, message, details) {
11
- super(message);
12
- this.code = code;
13
- this.details = details;
14
- this.name = 'GuildCLIError';
15
- }
16
- }
17
- /**
18
- * Common error codes
19
- */
20
- export const ErrorCodes = {
21
- // Network errors
22
- NETWORK_ERROR: 'NETWORK_ERROR',
23
- CONN_REFUSED: 'ECONNREFUSED',
24
- TIMEOUT: 'ETIMEDOUT',
25
- DNS_ERROR: 'ENOTFOUND',
26
- REQUEST_ABORTED: 'ECONNABORTED',
27
- REQUEST_CANCELED: 'ERR_CANCELED',
28
- // Auth errors
29
- AUTH_FAILED: 'AUTH_FAILED',
30
- AUTH_TOKEN_EXPIRED: 'AUTH_TOKEN_EXPIRED',
31
- AUTH_TOKEN_INVALID: 'AUTH_TOKEN_INVALID',
32
- AUTH_REQUIRED: 'AUTH_REQUIRED',
33
- // IAP errors (Google Identity-Aware Proxy)
34
- IAP_NOT_AUTHENTICATED: 'IAP_NOT_AUTHENTICATED',
35
- IAP_GCLOUD_NOT_FOUND: 'IAP_GCLOUD_NOT_FOUND',
36
- IAP_ACCESS_DENIED: 'IAP_ACCESS_DENIED',
37
- // Permission errors
38
- FORBIDDEN: 'FORBIDDEN',
39
- // API errors
40
- API_ERROR: 'API_ERROR',
41
- NOT_FOUND: 'NOT_FOUND',
42
- BAD_REQUEST: 'BAD_REQUEST',
43
- SERVER_ERROR: 'SERVER_ERROR',
44
- // Resource errors
45
- RESOURCE_EXISTS: 'RESOURCE_EXISTS',
46
- RESOURCE_NOT_FOUND: 'RESOURCE_NOT_FOUND',
47
- // Operation errors
48
- OPERATION_FAILED: 'OPERATION_FAILED',
49
- TIMEOUT_ERROR: 'TIMEOUT_ERROR',
50
- VALIDATION_ERROR: 'VALIDATION_ERROR',
51
- };
52
- /**
53
- * Check if debug mode is enabled (CLI flag or config)
54
- */
55
- export function isDebugMode() {
56
- return process.argv.includes('--debug') || getConfigFlag('debug');
57
- }
58
- /**
59
- * Log debug message if debug mode is enabled
60
- */
61
- export function debug(message, ...args) {
62
- if (isDebugMode()) {
63
- console.error(`[DEBUG] ${message}`, ...args);
64
- }
65
- }
66
- /**
67
- * Format error for output
68
- */
69
- export function formatError(error, details, code, stack, suggestions) {
70
- const result = {
71
- error,
72
- details,
73
- };
74
- if (code) {
75
- result.code = code;
76
- }
77
- if (isDebugMode() && stack) {
78
- result.stack = stack;
79
- }
80
- if (suggestions && suggestions.length > 0) {
81
- result.suggestions = suggestions;
82
- }
83
- return result;
84
- }
85
- /**
86
- * Get user-friendly error message for common error codes
87
- */
88
- export function getFriendlyErrorMessage(code, originalMessage) {
89
- switch (code) {
90
- case ErrorCodes.CONN_REFUSED:
91
- return {
92
- error: 'Connection refused',
93
- details: 'Cannot connect to Guild servers.',
94
- suggestions: ['Check your network connection', 'Try again in a moment'],
95
- };
96
- case ErrorCodes.TIMEOUT:
97
- return {
98
- error: 'Request timeout',
99
- details: 'Server took too long to respond',
100
- suggestions: [
101
- 'Check your network connection',
102
- 'Try again in a moment',
103
- 'Server may be experiencing high load',
104
- ],
105
- };
106
- case ErrorCodes.DNS_ERROR:
107
- return {
108
- error: 'DNS lookup failed',
109
- details: 'Could not resolve server hostname',
110
- suggestions: [
111
- 'Check your internet connection',
112
- 'Verify the server URL is correct',
113
- 'Check DNS settings',
114
- ],
115
- };
116
- case ErrorCodes.REQUEST_CANCELED:
117
- return {
118
- error: 'Request canceled',
119
- details: 'The request was canceled before completion',
120
- };
121
- case ErrorCodes.REQUEST_ABORTED:
122
- return {
123
- error: 'Request aborted',
124
- details: 'The connection was aborted before receiving a response',
125
- suggestions: ['Check if the server is running', 'Verify network connectivity'],
126
- };
127
- case ErrorCodes.AUTH_TOKEN_EXPIRED:
128
- return {
129
- error: 'Authentication token expired',
130
- details: 'Your session has expired. Please log in again.',
131
- suggestions: ['Run: guild auth login'],
132
- };
133
- case ErrorCodes.AUTH_TOKEN_INVALID:
134
- return {
135
- error: 'Invalid authentication token',
136
- details: 'Your authentication token is invalid or corrupted.',
137
- suggestions: ['Run: guild auth logout', 'Then: guild auth login'],
138
- };
139
- case ErrorCodes.FORBIDDEN:
140
- return {
141
- error: 'Permission denied',
142
- details: originalMessage || 'You do not have permission to perform this action.',
143
- suggestions: [
144
- 'Check that you have access to this resource',
145
- 'If this is an organization resource, verify your membership and permissions',
146
- ],
147
- };
148
- case ErrorCodes.AUTH_REQUIRED:
149
- return {
150
- error: 'Authentication required',
151
- details: 'This operation requires authentication.',
152
- suggestions: ['Run: guild auth login'],
153
- };
154
- case ErrorCodes.NOT_FOUND:
155
- return {
156
- error: 'Resource not found',
157
- details: originalMessage || 'The requested resource does not exist',
158
- };
159
- case ErrorCodes.SERVER_ERROR:
160
- return {
161
- error: 'Internal server error',
162
- details: originalMessage ||
163
- 'The server encountered an error while processing your request.',
164
- };
165
- default:
166
- return {
167
- error: 'Operation failed',
168
- details: originalMessage || 'An unexpected error occurred',
169
- };
170
- }
171
- }
172
- /**
173
- * Handle axios error and return standardized error
174
- */
175
- export function handleAxiosError(error) {
176
- debug('Axios error:', error);
177
- // Type guard for axios-like errors
178
- const isAxiosError = (err) => {
179
- return typeof err === 'object' && err !== null;
180
- };
181
- // Helper to safely extract message from unknown data
182
- const getErrorMessage = (data) => {
183
- // Try to extract message or error from JSON object
184
- if (typeof data === 'object' && data !== null) {
185
- if ('message' in data) {
186
- const msg = data.message;
187
- if (typeof msg === 'string')
188
- return msg;
189
- }
190
- if ('error' in data) {
191
- const err = data.error;
192
- if (typeof err === 'string')
193
- return err;
194
- }
195
- }
196
- // If data is a string, return first 200 chars (likely HTML or plain text error)
197
- if (typeof data === 'string' && data.length > 0) {
198
- const cleaned = data.replace(/<[^>]*>/g, '').trim(); // Strip HTML tags
199
- return cleaned.substring(0, 200);
200
- }
201
- return undefined;
202
- };
203
- if (!isAxiosError(error)) {
204
- return formatError('Unknown error', String(error));
205
- }
206
- if (error.code === ErrorCodes.AUTH_REQUIRED) {
207
- const friendly = getFriendlyErrorMessage(ErrorCodes.AUTH_REQUIRED, error.message || 'Authentication required');
208
- return formatError(friendly.error, friendly.details, ErrorCodes.AUTH_REQUIRED, error.stack);
209
- }
210
- if (error.code === ErrorCodes.CONN_REFUSED) {
211
- const friendly = getFriendlyErrorMessage(ErrorCodes.CONN_REFUSED, error.message || 'Connection refused');
212
- return formatError(friendly.error, friendly.details, ErrorCodes.CONN_REFUSED, error.stack);
213
- }
214
- if (error.code === ErrorCodes.TIMEOUT) {
215
- const friendly = getFriendlyErrorMessage(ErrorCodes.TIMEOUT, error.message || 'Timeout');
216
- return formatError(friendly.error, friendly.details, ErrorCodes.TIMEOUT, error.stack);
217
- }
218
- if (error.code === ErrorCodes.DNS_ERROR) {
219
- const friendly = getFriendlyErrorMessage(ErrorCodes.DNS_ERROR, error.message || 'DNS error');
220
- return formatError(friendly.error, friendly.details, ErrorCodes.DNS_ERROR, error.stack);
221
- }
222
- if (error.code === ErrorCodes.REQUEST_CANCELED) {
223
- const friendly = getFriendlyErrorMessage(ErrorCodes.REQUEST_CANCELED, error.message || 'Request canceled');
224
- return formatError(friendly.error, friendly.details, ErrorCodes.REQUEST_CANCELED, error.stack);
225
- }
226
- if (error.code === ErrorCodes.REQUEST_ABORTED) {
227
- const friendly = getFriendlyErrorMessage(ErrorCodes.REQUEST_ABORTED, error.message || 'Request aborted');
228
- return formatError(friendly.error, friendly.details, ErrorCodes.REQUEST_ABORTED, error.stack);
229
- }
230
- if (error.response) {
231
- const status = error.response.status;
232
- const data = error.response.data;
233
- // Check for auth errors
234
- if (status === 401) {
235
- const friendly = getFriendlyErrorMessage(ErrorCodes.AUTH_REQUIRED, getErrorMessage(data) || '');
236
- return formatError(friendly.error, friendly.details, ErrorCodes.AUTH_REQUIRED, error.stack);
237
- }
238
- if (status === 403) {
239
- const friendly = getFriendlyErrorMessage(ErrorCodes.FORBIDDEN, getErrorMessage(data) || '');
240
- return formatError(friendly.error, friendly.details, ErrorCodes.FORBIDDEN, error.stack);
241
- }
242
- if (status === 404) {
243
- const friendly = getFriendlyErrorMessage(ErrorCodes.NOT_FOUND, getErrorMessage(data) || '');
244
- return formatError(friendly.error, friendly.details, ErrorCodes.NOT_FOUND, error.stack);
245
- }
246
- if (status === 409) {
247
- // Resource already exists / conflict
248
- return formatError('Resource already exists', getErrorMessage(data) || 'The resource you are trying to create already exists', ErrorCodes.RESOURCE_EXISTS, error.stack);
249
- }
250
- if (status >= 500) {
251
- const friendly = getFriendlyErrorMessage(ErrorCodes.SERVER_ERROR, getErrorMessage(data) || '');
252
- // Include backend traceback if available (for debugging CI issues)
253
- const backendTraceback = data?.traceback;
254
- const details = backendTraceback
255
- ? `${friendly.details}\n\nBackend traceback:\n${backendTraceback}`
256
- : friendly.details;
257
- return formatError(friendly.error, details, ErrorCodes.SERVER_ERROR, error.stack, friendly.suggestions);
258
- }
259
- // Generic API error
260
- return formatError(`API error: ${status}`, getErrorMessage(data) || error.message || 'Unknown error', ErrorCodes.API_ERROR, error.stack);
261
- }
262
- // Pass through the actual error - don't claim it's a network error
263
- return formatError('Unexpected error', error.message || 'An unknown error occurred', undefined, error.stack);
264
- }
265
- /**
266
- * Patterns that indicate IAP authentication errors
267
- */
268
- const IAP_ERROR_PATTERNS = [
269
- 'Not authenticated to Google Cloud',
270
- 'gcloud CLI not found',
271
- 'Access denied to service account',
272
- 'gcloud returned empty token',
273
- ];
274
- /**
275
- * Messages from Guildcore that indicate a real Guild auth failure.
276
- * Source: python/guildcore/core/session.py and routing.py
277
- */
278
- const GUILD_AUTH_FAILURE_MESSAGES = [
279
- 'Access token expired',
280
- 'Access token invalid',
281
- 'Session expired',
282
- 'Not authenticated',
283
- ];
284
- /**
285
- * Check if an error is an IAP (Google Identity-Aware Proxy) error
286
- */
287
- export function isIapError(error) {
288
- const message = error instanceof Error ? error.message : String(error);
289
- return IAP_ERROR_PATTERNS.some((pattern) => message.includes(pattern));
290
- }
291
- /**
292
- * Check if an error is a Guild auth error
293
- */
294
- export function isAuthError(error) {
295
- const message = error instanceof Error ? error.message : String(error);
296
- return GUILD_AUTH_FAILURE_MESSAGES.some((pattern) => message.includes(pattern));
297
- }
298
- /**
299
- * Check if a 401 response message indicates the stored auth token should be cleared.
300
- * Uses exact match — only clear for known Guild auth failures.
301
- */
302
- export function shouldClearAuthToken(responseMessage) {
303
- if (!responseMessage)
304
- return false;
305
- return GUILD_AUTH_FAILURE_MESSAGES.some((msg) => msg === responseMessage);
306
- }
307
- /**
308
- * Check if an error is fatal (should not be retried)
309
- *
310
- * Fatal errors include:
311
- * - IAP authentication failures (need gcloud auth login)
312
- * - Guild authentication failures (need guild auth login)
313
- * - 4xx HTTP errors (client errors, not transient)
314
- */
315
- export function isFatalError(error) {
316
- // IAP and auth errors are fatal
317
- if (isIapError(error) || isAuthError(error)) {
318
- return true;
319
- }
320
- // Check for 4xx HTTP status codes (client errors)
321
- if (typeof error === 'object' && error !== null) {
322
- const err = error;
323
- if (err.response?.status &&
324
- err.response.status >= 400 &&
325
- err.response.status < 500) {
326
- return true;
327
- }
328
- }
329
- return false;
330
- }
331
- /**
332
- * Check if an error is retryable (transient network/server issues)
333
- */
334
- export function isRetryableError(error) {
335
- // Fatal errors should not be retried
336
- if (isFatalError(error)) {
337
- return false;
338
- }
339
- // Check for known retryable error codes
340
- if (typeof error === 'object' && error !== null) {
341
- const err = error;
342
- return (err.code === ErrorCodes.CONN_REFUSED ||
343
- err.code === ErrorCodes.TIMEOUT ||
344
- err.code === ErrorCodes.DNS_ERROR ||
345
- err.code === ErrorCodes.REQUEST_ABORTED ||
346
- (err.response !== undefined && err.response.status >= 500));
347
- }
348
- return false;
349
- }
350
- /**
351
- * Retry a function with exponential backoff
352
- */
353
- export async function retry(fn, options = {}) {
354
- const { maxAttempts = 3, initialDelay = 1000, maxDelay = 10000, backoffMultiplier = 2, shouldRetry = isRetryableError, } = options;
355
- let lastError;
356
- let delay = initialDelay;
357
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
358
- try {
359
- debug(`Attempt ${attempt}/${maxAttempts}`);
360
- return await fn();
361
- }
362
- catch (error) {
363
- lastError = error;
364
- if (attempt === maxAttempts || !shouldRetry(error)) {
365
- throw error;
366
- }
367
- const errorMsg = error instanceof Error ? error.message : String(error);
368
- debug(`Attempt ${attempt} failed, retrying in ${delay}ms...`, errorMsg);
369
- await new Promise((resolve) => setTimeout(resolve, delay));
370
- delay = Math.min(delay * backoffMultiplier, maxDelay);
371
- }
372
- }
373
- throw lastError;
374
- }
375
- //# sourceMappingURL=errors.js.map