bktide 0.0.1

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/README.md +145 -0
  2. package/WORKFLOW_README.md +65 -0
  3. package/bin/alfred-entrypoint +54 -0
  4. package/dist/commands/BaseCommand.js +159 -0
  5. package/dist/commands/BaseCommand.js.map +1 -0
  6. package/dist/commands/BaseCommandHandler.js +80 -0
  7. package/dist/commands/BaseCommandHandler.js.map +1 -0
  8. package/dist/commands/BuildCommandHandler.js +28 -0
  9. package/dist/commands/BuildCommandHandler.js.map +1 -0
  10. package/dist/commands/HelloCommandHandler.js +6 -0
  11. package/dist/commands/HelloCommandHandler.js.map +1 -0
  12. package/dist/commands/ListAnnotations.js +60 -0
  13. package/dist/commands/ListAnnotations.js.map +1 -0
  14. package/dist/commands/ListBuilds.js +137 -0
  15. package/dist/commands/ListBuilds.js.map +1 -0
  16. package/dist/commands/ListOrganizations.js +27 -0
  17. package/dist/commands/ListOrganizations.js.map +1 -0
  18. package/dist/commands/ListPipelines.js +114 -0
  19. package/dist/commands/ListPipelines.js.map +1 -0
  20. package/dist/commands/ManageToken.js +180 -0
  21. package/dist/commands/ManageToken.js.map +1 -0
  22. package/dist/commands/OrganizationCommandHandler.js +53 -0
  23. package/dist/commands/OrganizationCommandHandler.js.map +1 -0
  24. package/dist/commands/PipelineCommandHandler.js +142 -0
  25. package/dist/commands/PipelineCommandHandler.js.map +1 -0
  26. package/dist/commands/ShowViewer.js +26 -0
  27. package/dist/commands/ShowViewer.js.map +1 -0
  28. package/dist/commands/UserBuildsCommandHandler.js +61 -0
  29. package/dist/commands/UserBuildsCommandHandler.js.map +1 -0
  30. package/dist/commands/ViewerBuildsCommandHandler.js +176 -0
  31. package/dist/commands/ViewerBuildsCommandHandler.js.map +1 -0
  32. package/dist/commands/ViewerCommandHandler.js +46 -0
  33. package/dist/commands/ViewerCommandHandler.js.map +1 -0
  34. package/dist/commands/index.js +8 -0
  35. package/dist/commands/index.js.map +1 -0
  36. package/dist/formatters/BaseFormatter.js +14 -0
  37. package/dist/formatters/BaseFormatter.js.map +1 -0
  38. package/dist/formatters/FormatterFactory.js +48 -0
  39. package/dist/formatters/FormatterFactory.js.map +1 -0
  40. package/dist/formatters/annotations/Formatter.js +10 -0
  41. package/dist/formatters/annotations/Formatter.js.map +1 -0
  42. package/dist/formatters/annotations/JsonFormatter.js +20 -0
  43. package/dist/formatters/annotations/JsonFormatter.js.map +1 -0
  44. package/dist/formatters/annotations/PlainTextFormatter.js +35 -0
  45. package/dist/formatters/annotations/PlainTextFormatter.js.map +1 -0
  46. package/dist/formatters/annotations/index.js +23 -0
  47. package/dist/formatters/annotations/index.js.map +1 -0
  48. package/dist/formatters/builds/AlfredFormatter.js +135 -0
  49. package/dist/formatters/builds/AlfredFormatter.js.map +1 -0
  50. package/dist/formatters/builds/Formatter.js +10 -0
  51. package/dist/formatters/builds/Formatter.js.map +1 -0
  52. package/dist/formatters/builds/JsonFormatter.js +44 -0
  53. package/dist/formatters/builds/JsonFormatter.js.map +1 -0
  54. package/dist/formatters/builds/PlainTextFormatter.js +113 -0
  55. package/dist/formatters/builds/PlainTextFormatter.js.map +1 -0
  56. package/dist/formatters/builds/index.js +26 -0
  57. package/dist/formatters/builds/index.js.map +1 -0
  58. package/dist/formatters/errors/AlfredFormatter.js +110 -0
  59. package/dist/formatters/errors/AlfredFormatter.js.map +1 -0
  60. package/dist/formatters/errors/Formatter.js +98 -0
  61. package/dist/formatters/errors/Formatter.js.map +1 -0
  62. package/dist/formatters/errors/JsonFormatter.js +63 -0
  63. package/dist/formatters/errors/JsonFormatter.js.map +1 -0
  64. package/dist/formatters/errors/PlainTextFormatter.js +52 -0
  65. package/dist/formatters/errors/PlainTextFormatter.js.map +1 -0
  66. package/dist/formatters/errors/index.js +26 -0
  67. package/dist/formatters/errors/index.js.map +1 -0
  68. package/dist/formatters/index.js +9 -0
  69. package/dist/formatters/index.js.map +1 -0
  70. package/dist/formatters/organizations/Formatter.js +10 -0
  71. package/dist/formatters/organizations/Formatter.js.map +1 -0
  72. package/dist/formatters/organizations/JsonFormatter.js +16 -0
  73. package/dist/formatters/organizations/JsonFormatter.js.map +1 -0
  74. package/dist/formatters/organizations/PlainTextFormatter.js +15 -0
  75. package/dist/formatters/organizations/PlainTextFormatter.js.map +1 -0
  76. package/dist/formatters/organizations/index.js +21 -0
  77. package/dist/formatters/organizations/index.js.map +1 -0
  78. package/dist/formatters/pipelines/AlfredFormatter.js +42 -0
  79. package/dist/formatters/pipelines/AlfredFormatter.js.map +1 -0
  80. package/dist/formatters/pipelines/Formatter.js +10 -0
  81. package/dist/formatters/pipelines/Formatter.js.map +1 -0
  82. package/dist/formatters/pipelines/JsonFormatter.js +13 -0
  83. package/dist/formatters/pipelines/JsonFormatter.js.map +1 -0
  84. package/dist/formatters/pipelines/PlainTextFormatter.js +47 -0
  85. package/dist/formatters/pipelines/PlainTextFormatter.js.map +1 -0
  86. package/dist/formatters/pipelines/index.js +28 -0
  87. package/dist/formatters/pipelines/index.js.map +1 -0
  88. package/dist/formatters/token/AlfredFormatter.js +191 -0
  89. package/dist/formatters/token/AlfredFormatter.js.map +1 -0
  90. package/dist/formatters/token/Formatter.js +13 -0
  91. package/dist/formatters/token/Formatter.js.map +1 -0
  92. package/dist/formatters/token/JsonFormatter.js +211 -0
  93. package/dist/formatters/token/JsonFormatter.js.map +1 -0
  94. package/dist/formatters/token/PlainTextFormatter.js +184 -0
  95. package/dist/formatters/token/PlainTextFormatter.js.map +1 -0
  96. package/dist/formatters/token/index.js +26 -0
  97. package/dist/formatters/token/index.js.map +1 -0
  98. package/dist/formatters/viewer/Formatter.js +10 -0
  99. package/dist/formatters/viewer/Formatter.js.map +1 -0
  100. package/dist/formatters/viewer/JsonFormatter.js +20 -0
  101. package/dist/formatters/viewer/JsonFormatter.js.map +1 -0
  102. package/dist/formatters/viewer/PlainTextFormatter.js +20 -0
  103. package/dist/formatters/viewer/PlainTextFormatter.js.map +1 -0
  104. package/dist/formatters/viewer/index.js +21 -0
  105. package/dist/formatters/viewer/index.js.map +1 -0
  106. package/dist/graphql/generated/fragment-masking.js +17 -0
  107. package/dist/graphql/generated/fragment-masking.js.map +1 -0
  108. package/dist/graphql/generated/gql.js +13 -0
  109. package/dist/graphql/generated/gql.js.map +1 -0
  110. package/dist/graphql/generated/graphql.js +852 -0
  111. package/dist/graphql/generated/graphql.js.map +1 -0
  112. package/dist/graphql/generated/index.js +3 -0
  113. package/dist/graphql/generated/index.js.map +1 -0
  114. package/dist/graphql/generated/sdk.js +872 -0
  115. package/dist/graphql/generated/sdk.js.map +1 -0
  116. package/dist/graphql/queries.js +138 -0
  117. package/dist/graphql/queries.js.map +1 -0
  118. package/dist/index.js +271 -0
  119. package/dist/index.js.map +1 -0
  120. package/dist/services/BuildkiteClient.js +520 -0
  121. package/dist/services/BuildkiteClient.js.map +1 -0
  122. package/dist/services/BuildkiteRestClient.js +244 -0
  123. package/dist/services/BuildkiteRestClient.js.map +1 -0
  124. package/dist/services/CacheManager.js +221 -0
  125. package/dist/services/CacheManager.js.map +1 -0
  126. package/dist/services/CredentialManager.js +158 -0
  127. package/dist/services/CredentialManager.js.map +1 -0
  128. package/dist/services/EnhancedBuildkiteClient.js +297 -0
  129. package/dist/services/EnhancedBuildkiteClient.js.map +1 -0
  130. package/dist/services/logger.js +107 -0
  131. package/dist/services/logger.js.map +1 -0
  132. package/dist/types/buildkite.js +5 -0
  133. package/dist/types/buildkite.js.map +1 -0
  134. package/dist/types/credentials.js +2 -0
  135. package/dist/types/credentials.js.map +1 -0
  136. package/dist/types/index.js +3 -0
  137. package/dist/types/index.js.map +1 -0
  138. package/dist/utils/cli-error-handler.js +172 -0
  139. package/dist/utils/cli-error-handler.js.map +1 -0
  140. package/dist/utils/errorUtils.js +59 -0
  141. package/dist/utils/errorUtils.js.map +1 -0
  142. package/dist/utils/parseBuildRef.js +31 -0
  143. package/dist/utils/parseBuildRef.js.map +1 -0
  144. package/dist/utils/textFormatter.js +53 -0
  145. package/dist/utils/textFormatter.js.map +1 -0
  146. package/dist/utils/xdgPaths.js +95 -0
  147. package/dist/utils/xdgPaths.js.map +1 -0
  148. package/env.example +66 -0
  149. package/icons/README.md +68 -0
  150. package/icons/blocked.png +0 -0
  151. package/icons/buildkite.png +0 -0
  152. package/icons/failed.png +0 -0
  153. package/icons/failing.png +0 -0
  154. package/icons/passed.png +0 -0
  155. package/icons/running.png +0 -0
  156. package/icons/scheduled.png +0 -0
  157. package/icons/skipped.png +0 -0
  158. package/icons/unknown.png +0 -0
  159. package/info.plist +734 -0
  160. package/package.json +87 -0
@@ -0,0 +1,158 @@
1
+ import { Entry } from '@napi-rs/keyring';
2
+ import { logger } from './logger.js';
3
+ import { BuildkiteClient } from './BuildkiteClient.js';
4
+ import { BuildkiteRestClient } from './BuildkiteRestClient.js';
5
+ const SERVICE_NAME = 'bktide';
6
+ const ACCOUNT_KEY = 'default';
7
+ /**
8
+ * Manages secure storage of credentials using the system's keychain
9
+ */
10
+ export class CredentialManager {
11
+ entry;
12
+ constructor(serviceName = SERVICE_NAME, accountName = ACCOUNT_KEY) {
13
+ this.entry = new Entry(serviceName, accountName);
14
+ }
15
+ /**
16
+ * Stores a token in the system keychain
17
+ * @param token The Buildkite API token to store
18
+ * @returns true if token was successfully stored
19
+ */
20
+ async saveToken(token) {
21
+ try {
22
+ await this.entry.setPassword(token);
23
+ logger.debug('Token saved to system keychain');
24
+ return true;
25
+ }
26
+ catch (error) {
27
+ logger.error('Failed to save token to system keychain', error);
28
+ return false;
29
+ }
30
+ }
31
+ /**
32
+ * Retrieves the stored token from the system keychain
33
+ * @returns The stored token or undefined if not found
34
+ */
35
+ async getToken() {
36
+ try {
37
+ const token = this.entry.getPassword();
38
+ return token || undefined;
39
+ }
40
+ catch (error) {
41
+ return undefined;
42
+ }
43
+ }
44
+ /**
45
+ * Deletes the stored token from the system keychain
46
+ * @returns true if token was successfully deleted
47
+ */
48
+ async deleteToken() {
49
+ try {
50
+ await this.entry.deletePassword();
51
+ logger.debug('Token deleted from system keychain');
52
+ return true;
53
+ }
54
+ catch (error) {
55
+ logger.error('Failed to delete token from system keychain', error);
56
+ return false;
57
+ }
58
+ }
59
+ /**
60
+ * Checks if a token exists in the system keychain
61
+ * @returns true if a token exists
62
+ */
63
+ async hasToken() {
64
+ const token = await this.getToken();
65
+ return !!token;
66
+ }
67
+ /**
68
+ * Validates if a token is valid by making test API calls to both GraphQL and REST APIs
69
+ * @param token Optional token to validate. If not provided, will use the stored token.
70
+ * @returns Object containing validation status for both GraphQL and REST APIs
71
+ */
72
+ async validateToken(token) {
73
+ try {
74
+ // If no token provided, try to get the stored one
75
+ const tokenToValidate = token || await this.getToken();
76
+ if (!tokenToValidate) {
77
+ logger.debug('No token provided for validation');
78
+ return {
79
+ valid: false,
80
+ canListOrganizations: false,
81
+ organizations: {}
82
+ };
83
+ }
84
+ // Create clients with the token
85
+ const graphqlClient = new BuildkiteClient(tokenToValidate, { debug: false, caching: false });
86
+ const restClient = new BuildkiteRestClient(tokenToValidate, { debug: false });
87
+ // First check if we can list organizations
88
+ let orgSlugs = [];
89
+ try {
90
+ orgSlugs = await graphqlClient.getOrganizations().then(orgs => orgs.map(org => org.slug));
91
+ logger.debug('Successfully retrieved organization slugs');
92
+ }
93
+ catch (error) {
94
+ logger.debug('Failed to retrieve organization slugs', {
95
+ error: error instanceof Error ? error.message : String(error),
96
+ cause: error instanceof Error && error.cause ? error.cause : undefined
97
+ });
98
+ return {
99
+ valid: false,
100
+ canListOrganizations: false,
101
+ organizations: {}
102
+ };
103
+ }
104
+ const organizations = {};
105
+ let allValid = true;
106
+ // Validate each organization
107
+ for (const orgSlug of orgSlugs) {
108
+ const orgStatus = {
109
+ graphql: false,
110
+ builds: false,
111
+ organizations: false
112
+ };
113
+ try {
114
+ // Check GraphQL access
115
+ await graphqlClient.getViewer();
116
+ orgStatus.graphql = true;
117
+ }
118
+ catch (error) {
119
+ logger.debug(`GraphQL validation failed for organization ${orgSlug}`, error);
120
+ allValid = false;
121
+ }
122
+ try {
123
+ // Check build access
124
+ await restClient.hasBuildAccess(orgSlug);
125
+ orgStatus.builds = true;
126
+ }
127
+ catch (error) {
128
+ logger.debug(`Build access validation failed for organization ${orgSlug}`, error);
129
+ allValid = false;
130
+ }
131
+ try {
132
+ // Check organization access
133
+ await restClient.hasOrganizationAccess(orgSlug);
134
+ orgStatus.organizations = true;
135
+ }
136
+ catch (error) {
137
+ logger.debug(`Organization access validation failed for organization ${orgSlug}`, error);
138
+ allValid = false;
139
+ }
140
+ organizations[orgSlug] = orgStatus;
141
+ }
142
+ return {
143
+ valid: allValid,
144
+ canListOrganizations: true,
145
+ organizations
146
+ };
147
+ }
148
+ catch (error) {
149
+ logger.debug('Token validation failed', error);
150
+ return {
151
+ valid: false,
152
+ canListOrganizations: false,
153
+ organizations: {}
154
+ };
155
+ }
156
+ }
157
+ }
158
+ //# sourceMappingURL=CredentialManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CredentialManager.js","sourceRoot":"/","sources":["services/CredentialManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { Entry } from '@napi-rs/keyring';\nimport { logger } from './logger.js';\nimport { BuildkiteClient } from './BuildkiteClient.js';\nimport { BuildkiteRestClient } from './BuildkiteRestClient.js';\nimport { TokenValidationStatus, OrganizationValidationStatus } from '../types/credentials.js';\n\nconst SERVICE_NAME = 'bktide';\nconst ACCOUNT_KEY = 'default';\n\n/**\n * Manages secure storage of credentials using the system's keychain\n */\nexport class CredentialManager {\n private entry: Entry;\n\n constructor(serviceName = SERVICE_NAME, accountName = ACCOUNT_KEY) {\n this.entry = new Entry(serviceName, accountName);\n }\n\n /**\n * Stores a token in the system keychain\n * @param token The Buildkite API token to store\n * @returns true if token was successfully stored\n */\n async saveToken(token: string): Promise<boolean> {\n try {\n await this.entry.setPassword(token);\n logger.debug('Token saved to system keychain');\n return true;\n } catch (error) {\n logger.error('Failed to save token to system keychain', error);\n return false;\n }\n }\n\n /**\n * Retrieves the stored token from the system keychain\n * @returns The stored token or undefined if not found\n */\n async getToken(): Promise<string | undefined> {\n try {\n const token = this.entry.getPassword();\n return token || undefined;\n } catch (error) {\n return undefined;\n }\n }\n\n /**\n * Deletes the stored token from the system keychain\n * @returns true if token was successfully deleted\n */\n async deleteToken(): Promise<boolean> {\n try {\n await this.entry.deletePassword();\n logger.debug('Token deleted from system keychain');\n return true;\n } catch (error) {\n logger.error('Failed to delete token from system keychain', error);\n return false;\n }\n }\n\n /**\n * Checks if a token exists in the system keychain\n * @returns true if a token exists\n */\n async hasToken(): Promise<boolean> {\n const token = await this.getToken();\n return !!token;\n }\n\n /**\n * Validates if a token is valid by making test API calls to both GraphQL and REST APIs\n * @param token Optional token to validate. If not provided, will use the stored token.\n * @returns Object containing validation status for both GraphQL and REST APIs\n */\n async validateToken(token?: string): Promise<TokenValidationStatus> {\n try {\n // If no token provided, try to get the stored one\n const tokenToValidate = token || await this.getToken();\n if (!tokenToValidate) {\n logger.debug('No token provided for validation');\n return { \n valid: false, \n canListOrganizations: false,\n organizations: {} \n };\n }\n\n // Create clients with the token\n const graphqlClient = new BuildkiteClient(tokenToValidate, { debug: false, caching: false });\n const restClient = new BuildkiteRestClient(tokenToValidate, { debug: false });\n \n // First check if we can list organizations\n let orgSlugs: string[] = [];\n try {\n orgSlugs = await graphqlClient.getOrganizations().then(orgs => orgs.map(org => org.slug));\n logger.debug('Successfully retrieved organization slugs');\n } catch (error) {\n logger.debug('Failed to retrieve organization slugs', {\n error: error instanceof Error ? error.message : String(error),\n cause: error instanceof Error && error.cause ? error.cause : undefined\n });\n return { \n valid: false, \n canListOrganizations: false,\n organizations: {} \n };\n }\n\n const organizations: Record<string, OrganizationValidationStatus> = {};\n let allValid = true;\n\n // Validate each organization\n for (const orgSlug of orgSlugs) {\n const orgStatus: OrganizationValidationStatus = {\n graphql: false,\n builds: false,\n organizations: false\n };\n\n try {\n // Check GraphQL access\n await graphqlClient.getViewer();\n orgStatus.graphql = true;\n } catch (error) {\n logger.debug(`GraphQL validation failed for organization ${orgSlug}`, error);\n allValid = false;\n }\n\n try {\n // Check build access\n await restClient.hasBuildAccess(orgSlug);\n orgStatus.builds = true;\n } catch (error) {\n logger.debug(`Build access validation failed for organization ${orgSlug}`, error);\n allValid = false;\n }\n\n try {\n // Check organization access\n await restClient.hasOrganizationAccess(orgSlug);\n orgStatus.organizations = true;\n } catch (error) {\n logger.debug(`Organization access validation failed for organization ${orgSlug}`, error);\n allValid = false;\n }\n\n organizations[orgSlug] = orgStatus;\n }\n\n return {\n valid: allValid,\n canListOrganizations: true,\n organizations\n };\n } catch (error) {\n logger.debug('Token validation failed', error);\n return { \n valid: false, \n canListOrganizations: false,\n organizations: {} \n };\n }\n }\n}"]}
@@ -0,0 +1,297 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { GraphQLClient } from 'graphql-request';
11
+ import { CacheManager } from './CacheManager.js';
12
+ import { GET_VIEWER, GET_ORGANIZATIONS, GET_PIPELINES, GET_BUILDS, GET_VIEWER_BUILDS } from '../graphql/queries.js';
13
+ // These imports will be available after running GraphQL codegen
14
+ import { getSdk } from '../graphql/generated/sdk.js';
15
+ /**
16
+ * EnhancedBuildkiteClient provides strongly-typed methods to interact with the Buildkite GraphQL API
17
+ */
18
+ export class EnhancedBuildkiteClient {
19
+ /**
20
+ * Create a new EnhancedBuildkiteClient
21
+ * @param token Your Buildkite API token
22
+ * @param options Configuration options
23
+ */
24
+ constructor(token, options, debug) {
25
+ this.baseUrl = 'https://graphql.buildkite.com/v1';
26
+ this.cacheManager = null;
27
+ this.debug = false;
28
+ this.token = token;
29
+ this.debug = debug || (options === null || options === void 0 ? void 0 : options.debug) || false;
30
+ if (options === null || options === void 0 ? void 0 : options.baseUrl) {
31
+ this.baseUrl = options.baseUrl;
32
+ }
33
+ this.client = new GraphQLClient(this.baseUrl, {
34
+ headers: {
35
+ Authorization: `Bearer ${this.token}`,
36
+ },
37
+ });
38
+ // Initialize the typed SDK
39
+ this.typedSdk = getSdk(this.client);
40
+ // Initialize cache if caching is enabled
41
+ if ((options === null || options === void 0 ? void 0 : options.caching) !== false) {
42
+ this.cacheManager = new CacheManager(options === null || options === void 0 ? void 0 : options.cacheTTLs);
43
+ // Initialize cache and set token hash (async, but we don't wait)
44
+ this.initCache();
45
+ }
46
+ }
47
+ /**
48
+ * Initialize cache asynchronously
49
+ */
50
+ initCache() {
51
+ return __awaiter(this, void 0, void 0, function* () {
52
+ if (this.cacheManager) {
53
+ yield this.cacheManager.init();
54
+ yield this.cacheManager.setTokenHash(this.token);
55
+ }
56
+ });
57
+ }
58
+ /**
59
+ * Get the current viewer information
60
+ * @returns The viewer data
61
+ */
62
+ getViewer() {
63
+ return __awaiter(this, void 0, void 0, function* () {
64
+ if (this.debug) {
65
+ console.debug(`🕒 Starting GraphQL query: GetViewer`);
66
+ }
67
+ // Check if result is in cache
68
+ if (this.cacheManager) {
69
+ const cachedResult = yield this.cacheManager.get(GET_VIEWER.toString(), {});
70
+ if (cachedResult) {
71
+ if (this.debug) {
72
+ console.debug(`✅ Served from cache: GetViewer`);
73
+ }
74
+ return cachedResult;
75
+ }
76
+ }
77
+ const startTime = process.hrtime.bigint();
78
+ const result = yield this.typedSdk.GetViewer();
79
+ // Store result in cache if caching is enabled
80
+ if (this.cacheManager) {
81
+ yield this.cacheManager.set(GET_VIEWER.toString(), result, {});
82
+ }
83
+ const endTime = process.hrtime.bigint();
84
+ const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
85
+ if (this.debug) {
86
+ console.debug(`✅ GraphQL query completed: GetViewer (${duration.toFixed(2)}ms)`);
87
+ }
88
+ return result;
89
+ });
90
+ }
91
+ /**
92
+ * Get the organizations for the current viewer
93
+ * @returns The organizations data
94
+ */
95
+ getOrganizations() {
96
+ return __awaiter(this, void 0, void 0, function* () {
97
+ if (this.debug) {
98
+ console.debug(`🕒 Starting GraphQL query: GetOrganizations`);
99
+ }
100
+ // Check if result is in cache
101
+ if (this.cacheManager) {
102
+ const cachedResult = yield this.cacheManager.get(GET_ORGANIZATIONS.toString(), {});
103
+ if (cachedResult) {
104
+ if (this.debug) {
105
+ console.debug(`✅ Served from cache: GetOrganizations`);
106
+ }
107
+ return cachedResult;
108
+ }
109
+ }
110
+ const startTime = process.hrtime.bigint();
111
+ const result = yield this.typedSdk.GetOrganizations();
112
+ // Store result in cache if caching is enabled
113
+ if (this.cacheManager) {
114
+ yield this.cacheManager.set(GET_ORGANIZATIONS.toString(), result, {});
115
+ }
116
+ const endTime = process.hrtime.bigint();
117
+ const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
118
+ if (this.debug) {
119
+ console.debug(`✅ GraphQL query completed: GetOrganizations (${duration.toFixed(2)}ms)`);
120
+ }
121
+ return result;
122
+ });
123
+ }
124
+ /**
125
+ * Get the organization slugs for the current viewer
126
+ * @returns An array of organization slugs the current user belongs to
127
+ */
128
+ getViewerOrganizationSlugs() {
129
+ return __awaiter(this, void 0, void 0, function* () {
130
+ var _a, _b;
131
+ try {
132
+ const startTime = process.hrtime.bigint();
133
+ if (this.debug) {
134
+ console.debug(`🕒 Starting GraphQL query: getViewerOrganizationSlugs`);
135
+ }
136
+ const data = yield this.getOrganizations();
137
+ if (!((_b = (_a = data === null || data === void 0 ? void 0 : data.viewer) === null || _a === void 0 ? void 0 : _a.organizations) === null || _b === void 0 ? void 0 : _b.edges)) {
138
+ throw new Error('Failed to fetch organizations from the API');
139
+ }
140
+ const orgs = data.viewer.organizations.edges.map((edge) => edge.node.slug);
141
+ if (orgs.length === 0) {
142
+ throw new Error('No organizations found for the current user');
143
+ }
144
+ const endTime = process.hrtime.bigint();
145
+ const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
146
+ if (this.debug) {
147
+ console.debug(`✅ Found ${orgs.length} organizations (${duration.toFixed(2)}ms)`);
148
+ }
149
+ return orgs;
150
+ }
151
+ catch (error) {
152
+ console.error('Error fetching viewer organizations:', error);
153
+ throw new Error('Failed to determine your organizations');
154
+ }
155
+ });
156
+ }
157
+ /**
158
+ * Get pipelines for an organization
159
+ * @param organizationSlug The organization slug
160
+ * @param first Number of pipelines to retrieve
161
+ * @param after Cursor for pagination
162
+ * @returns The pipelines data
163
+ */
164
+ getPipelines(organizationSlug, first, after) {
165
+ return __awaiter(this, void 0, void 0, function* () {
166
+ const variables = {
167
+ organizationSlug,
168
+ first,
169
+ after,
170
+ };
171
+ if (this.debug) {
172
+ console.debug(`🕒 Starting GraphQL query: GetPipelines for ${organizationSlug}`);
173
+ }
174
+ // Check if result is in cache
175
+ if (this.cacheManager) {
176
+ const cachedResult = yield this.cacheManager.get(GET_PIPELINES.toString(), variables);
177
+ if (cachedResult) {
178
+ if (this.debug) {
179
+ console.debug(`✅ Served from cache: GetPipelines`);
180
+ }
181
+ return cachedResult;
182
+ }
183
+ }
184
+ const startTime = process.hrtime.bigint();
185
+ const result = yield this.typedSdk.GetPipelines(variables);
186
+ // Store result in cache if caching is enabled
187
+ if (this.cacheManager) {
188
+ yield this.cacheManager.set(GET_PIPELINES.toString(), result, variables);
189
+ }
190
+ const endTime = process.hrtime.bigint();
191
+ const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
192
+ if (this.debug) {
193
+ console.debug(`✅ GraphQL query completed: GetPipelines (${duration.toFixed(2)}ms)`);
194
+ }
195
+ return result;
196
+ });
197
+ }
198
+ /**
199
+ * Get builds for a pipeline
200
+ * @param pipelineSlug The pipeline slug
201
+ * @param organizationSlug The organization slug
202
+ * @param first Number of builds to retrieve
203
+ * @returns The builds data
204
+ */
205
+ getBuilds(pipelineSlug, organizationSlug, first) {
206
+ return __awaiter(this, void 0, void 0, function* () {
207
+ const variables = {
208
+ pipelineSlug,
209
+ organizationSlug,
210
+ first,
211
+ };
212
+ if (this.debug) {
213
+ console.debug(`🕒 Starting GraphQL query: GetBuilds for ${pipelineSlug} in ${organizationSlug}`);
214
+ }
215
+ // Check if result is in cache
216
+ if (this.cacheManager) {
217
+ const cachedResult = yield this.cacheManager.get(GET_BUILDS.toString(), variables);
218
+ if (cachedResult) {
219
+ if (this.debug) {
220
+ console.debug(`✅ Served from cache: GetBuilds`);
221
+ }
222
+ return cachedResult;
223
+ }
224
+ }
225
+ const startTime = process.hrtime.bigint();
226
+ const result = yield this.typedSdk.GetBuilds(variables);
227
+ // Store result in cache if caching is enabled
228
+ if (this.cacheManager) {
229
+ yield this.cacheManager.set(GET_BUILDS.toString(), result, variables);
230
+ }
231
+ const endTime = process.hrtime.bigint();
232
+ const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
233
+ if (this.debug) {
234
+ console.debug(`✅ GraphQL query completed: GetBuilds (${duration.toFixed(2)}ms)`);
235
+ }
236
+ return result;
237
+ });
238
+ }
239
+ /**
240
+ * Get builds for the current viewer
241
+ * @param first Number of builds to retrieve
242
+ * @returns The viewer builds data
243
+ */
244
+ getViewerBuilds(first) {
245
+ return __awaiter(this, void 0, void 0, function* () {
246
+ const variables = {
247
+ first,
248
+ };
249
+ if (this.debug) {
250
+ console.debug(`🕒 Starting GraphQL query: GetViewerBuilds`);
251
+ }
252
+ // Check if result is in cache
253
+ if (this.cacheManager) {
254
+ const cachedResult = yield this.cacheManager.get(GET_VIEWER_BUILDS.toString(), variables);
255
+ if (cachedResult) {
256
+ if (this.debug) {
257
+ console.debug(`✅ Served from cache: GetViewerBuilds`);
258
+ }
259
+ return cachedResult;
260
+ }
261
+ }
262
+ const startTime = process.hrtime.bigint();
263
+ const result = yield this.typedSdk.GetViewerBuilds(variables);
264
+ // Store result in cache if caching is enabled
265
+ if (this.cacheManager) {
266
+ yield this.cacheManager.set(GET_VIEWER_BUILDS.toString(), result, variables);
267
+ }
268
+ const endTime = process.hrtime.bigint();
269
+ const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds
270
+ if (this.debug) {
271
+ console.debug(`✅ GraphQL query completed: GetViewerBuilds (${duration.toFixed(2)}ms)`);
272
+ }
273
+ return result;
274
+ });
275
+ }
276
+ /**
277
+ * Clear all cache entries
278
+ */
279
+ clearCache() {
280
+ return __awaiter(this, void 0, void 0, function* () {
281
+ if (this.cacheManager) {
282
+ yield this.cacheManager.clear();
283
+ }
284
+ });
285
+ }
286
+ /**
287
+ * Invalidate a specific cache type
288
+ */
289
+ invalidateCache(type) {
290
+ return __awaiter(this, void 0, void 0, function* () {
291
+ if (this.cacheManager) {
292
+ yield this.cacheManager.invalidateType(type);
293
+ }
294
+ });
295
+ }
296
+ }
297
+ //# sourceMappingURL=EnhancedBuildkiteClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EnhancedBuildkiteClient.js","sourceRoot":"/","sources":["services/EnhancedBuildkiteClient.ts"],"names":[],"mappings":"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","sourcesContent":["import { GraphQLClient } from 'graphql-request';\nimport { CacheManager } from './CacheManager.js';\nimport { BuildkiteClientOptions } from './BuildkiteClient.js';\nimport { \n GET_VIEWER, \n GET_ORGANIZATIONS, \n GET_PIPELINES, \n GET_BUILDS, \n GET_VIEWER_BUILDS \n} from '../graphql/queries.js';\n// These imports will be available after running GraphQL codegen\nimport { \n GetViewerQuery, \n GetOrganizationsQuery, \n GetPipelinesQuery,\n GetPipelinesQueryVariables,\n GetBuildsQuery,\n GetBuildsQueryVariables,\n GetViewerBuildsQuery,\n GetViewerBuildsQueryVariables,\n getSdk\n} from '../graphql/generated/sdk.js';\n\n/**\n * EnhancedBuildkiteClient provides strongly-typed methods to interact with the Buildkite GraphQL API\n */\nexport class EnhancedBuildkiteClient {\n private client: GraphQLClient;\n private typedSdk: ReturnType<typeof getSdk>;\n private token: string;\n private baseUrl: string = 'https://graphql.buildkite.com/v1';\n private cacheManager: CacheManager | null = null;\n private debug: boolean = false;\n\n /**\n * Create a new EnhancedBuildkiteClient\n * @param token Your Buildkite API token\n * @param options Configuration options\n */\n constructor(token: string, options?: BuildkiteClientOptions, debug?: boolean) {\n this.token = token;\n this.debug = debug || options?.debug || false;\n if (options?.baseUrl) {\n this.baseUrl = options.baseUrl;\n }\n\n this.client = new GraphQLClient(this.baseUrl, {\n headers: {\n Authorization: `Bearer ${this.token}`,\n },\n });\n\n // Initialize the typed SDK\n this.typedSdk = getSdk(this.client);\n\n // Initialize cache if caching is enabled\n if (options?.caching !== false) {\n this.cacheManager = new CacheManager(options?.cacheTTLs);\n // Initialize cache and set token hash (async, but we don't wait)\n this.initCache();\n }\n }\n\n /**\n * Initialize cache asynchronously\n */\n private async initCache(): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.init();\n await this.cacheManager.setTokenHash(this.token);\n }\n }\n\n /**\n * Get the current viewer information\n * @returns The viewer data\n */\n public async getViewer(): Promise<GetViewerQuery> {\n if (this.debug) {\n console.debug(`🕒 Starting GraphQL query: GetViewer`);\n }\n\n // Check if result is in cache\n if (this.cacheManager) {\n const cachedResult = await this.cacheManager.get<GetViewerQuery>(GET_VIEWER.toString(), {});\n if (cachedResult) {\n if (this.debug) {\n console.debug(`✅ Served from cache: GetViewer`);\n }\n return cachedResult;\n }\n }\n\n const startTime = process.hrtime.bigint();\n const result = await this.typedSdk.GetViewer();\n\n // Store result in cache if caching is enabled\n if (this.cacheManager) {\n await this.cacheManager.set(GET_VIEWER.toString(), result, {});\n }\n\n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n console.debug(`✅ GraphQL query completed: GetViewer (${duration.toFixed(2)}ms)`);\n }\n\n return result;\n }\n\n /**\n * Get the organizations for the current viewer\n * @returns The organizations data\n */\n public async getOrganizations(): Promise<GetOrganizationsQuery> {\n if (this.debug) {\n console.debug(`🕒 Starting GraphQL query: GetOrganizations`);\n }\n\n // Check if result is in cache\n if (this.cacheManager) {\n const cachedResult = await this.cacheManager.get<GetOrganizationsQuery>(GET_ORGANIZATIONS.toString(), {});\n if (cachedResult) {\n if (this.debug) {\n console.debug(`✅ Served from cache: GetOrganizations`);\n }\n return cachedResult;\n }\n }\n\n const startTime = process.hrtime.bigint();\n const result = await this.typedSdk.GetOrganizations();\n\n // Store result in cache if caching is enabled\n if (this.cacheManager) {\n await this.cacheManager.set(GET_ORGANIZATIONS.toString(), result, {});\n }\n\n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n console.debug(`✅ GraphQL query completed: GetOrganizations (${duration.toFixed(2)}ms)`);\n }\n\n return result;\n }\n\n /**\n * Get the organization slugs for the current viewer\n * @returns An array of organization slugs the current user belongs to\n */\n public async getViewerOrganizationSlugs(): Promise<string[]> {\n try {\n const startTime = process.hrtime.bigint();\n if (this.debug) {\n console.debug(`🕒 Starting GraphQL query: getViewerOrganizationSlugs`);\n }\n \n const data = await this.getOrganizations();\n \n if (!data?.viewer?.organizations?.edges) {\n throw new Error('Failed to fetch organizations from the API');\n }\n \n const orgs = data.viewer.organizations.edges.map((edge: { node: { slug: string } }) => edge.node.slug);\n \n if (orgs.length === 0) {\n throw new Error('No organizations found for the current user');\n }\n \n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n console.debug(`✅ Found ${orgs.length} organizations (${duration.toFixed(2)}ms)`);\n }\n \n return orgs;\n } catch (error) {\n console.error('Error fetching viewer organizations:', error);\n throw new Error('Failed to determine your organizations');\n }\n }\n\n /**\n * Get pipelines for an organization\n * @param organizationSlug The organization slug\n * @param first Number of pipelines to retrieve\n * @param after Cursor for pagination\n * @returns The pipelines data\n */\n public async getPipelines(\n organizationSlug: string, \n first?: number, \n after?: string\n ): Promise<GetPipelinesQuery> {\n const variables: GetPipelinesQueryVariables = {\n organizationSlug,\n first,\n after,\n };\n\n if (this.debug) {\n console.debug(`🕒 Starting GraphQL query: GetPipelines for ${organizationSlug}`);\n }\n\n // Check if result is in cache\n if (this.cacheManager) {\n const cachedResult = await this.cacheManager.get<GetPipelinesQuery>(GET_PIPELINES.toString(), variables);\n if (cachedResult) {\n if (this.debug) {\n console.debug(`✅ Served from cache: GetPipelines`);\n }\n return cachedResult;\n }\n }\n\n const startTime = process.hrtime.bigint();\n const result = await this.typedSdk.GetPipelines(variables);\n\n // Store result in cache if caching is enabled\n if (this.cacheManager) {\n await this.cacheManager.set(GET_PIPELINES.toString(), result, variables);\n }\n\n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n console.debug(`✅ GraphQL query completed: GetPipelines (${duration.toFixed(2)}ms)`);\n }\n\n return result;\n }\n\n /**\n * Get builds for a pipeline\n * @param pipelineSlug The pipeline slug\n * @param organizationSlug The organization slug\n * @param first Number of builds to retrieve\n * @returns The builds data\n */\n public async getBuilds(\n pipelineSlug: string,\n organizationSlug: string,\n first?: number\n ): Promise<GetBuildsQuery> {\n const variables: GetBuildsQueryVariables = {\n pipelineSlug,\n organizationSlug,\n first,\n };\n\n if (this.debug) {\n console.debug(`🕒 Starting GraphQL query: GetBuilds for ${pipelineSlug} in ${organizationSlug}`);\n }\n\n // Check if result is in cache\n if (this.cacheManager) {\n const cachedResult = await this.cacheManager.get<GetBuildsQuery>(GET_BUILDS.toString(), variables);\n if (cachedResult) {\n if (this.debug) {\n console.debug(`✅ Served from cache: GetBuilds`);\n }\n return cachedResult;\n }\n }\n\n const startTime = process.hrtime.bigint();\n const result = await this.typedSdk.GetBuilds(variables);\n\n // Store result in cache if caching is enabled\n if (this.cacheManager) {\n await this.cacheManager.set(GET_BUILDS.toString(), result, variables);\n }\n\n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n console.debug(`✅ GraphQL query completed: GetBuilds (${duration.toFixed(2)}ms)`);\n }\n\n return result;\n }\n\n /**\n * Get builds for the current viewer\n * @param first Number of builds to retrieve\n * @returns The viewer builds data\n */\n public async getViewerBuilds(first: number): Promise<GetViewerBuildsQuery> {\n const variables: GetViewerBuildsQueryVariables = {\n first,\n };\n\n if (this.debug) {\n console.debug(`🕒 Starting GraphQL query: GetViewerBuilds`);\n }\n\n // Check if result is in cache\n if (this.cacheManager) {\n const cachedResult = await this.cacheManager.get<GetViewerBuildsQuery>(GET_VIEWER_BUILDS.toString(), variables);\n if (cachedResult) {\n if (this.debug) {\n console.debug(`✅ Served from cache: GetViewerBuilds`);\n }\n return cachedResult;\n }\n }\n\n const startTime = process.hrtime.bigint();\n const result = await this.typedSdk.GetViewerBuilds(variables);\n\n // Store result in cache if caching is enabled\n if (this.cacheManager) {\n await this.cacheManager.set(GET_VIEWER_BUILDS.toString(), result, variables);\n }\n\n const endTime = process.hrtime.bigint();\n const duration = Number(endTime - startTime) / 1000000; // Convert to milliseconds\n if (this.debug) {\n console.debug(`✅ GraphQL query completed: GetViewerBuilds (${duration.toFixed(2)}ms)`);\n }\n\n return result;\n }\n\n /**\n * Clear all cache entries\n */\n public async clearCache(): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.clear();\n }\n }\n\n /**\n * Invalidate a specific cache type\n */\n public async invalidateCache(type: string): Promise<void> {\n if (this.cacheManager) {\n await this.cacheManager.invalidateType(type);\n }\n }\n} "]}
@@ -0,0 +1,107 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { pino } from 'pino';
4
+ import { XDGPaths } from '../utils/xdgPaths.js';
5
+ const logDir = XDGPaths.getAppLogDir('bktide');
6
+ fs.mkdirSync(logDir, { recursive: true });
7
+ const logFile = path.join(logDir, 'cli.log');
8
+ export const logger = pino({
9
+ level: process.env.LOG_LEVEL || 'info',
10
+ customLevels: {
11
+ console: 80
12
+ },
13
+ transport: {
14
+ targets: [
15
+ // Direct console output (no pretty formatting)
16
+ {
17
+ target: 'pino-pretty',
18
+ level: 'console',
19
+ options: {
20
+ colorize: false,
21
+ useOnlyCustomProps: true,
22
+ sync: true,
23
+ minimumLevel: 'console',
24
+ ignore: 'level,time,pid,hostname',
25
+ errorProps: 'err,error,stack,message,code,details'
26
+ }
27
+ },
28
+ // Debug output with pretty formatting
29
+ {
30
+ target: 'pino-pretty',
31
+ level: 'trace',
32
+ options: {
33
+ colorize: true,
34
+ sync: true,
35
+ translateTime: 'HH:MM:ss.l',
36
+ ignore: 'time,pid,hostname',
37
+ errorProps: 'err,error,stack,message,code,details'
38
+ }
39
+ },
40
+ // JSON file output for detailed logging
41
+ {
42
+ target: 'pino/file',
43
+ level: 'trace',
44
+ options: {
45
+ destination: logFile,
46
+ mkdir: true,
47
+ sync: false
48
+ }
49
+ }
50
+ ],
51
+ dedupe: true
52
+ },
53
+ serializers: {
54
+ err: pino.stdSerializers.err,
55
+ error: pino.stdSerializers.err,
56
+ stack: (stack) => stack,
57
+ details: (details) => details
58
+ }
59
+ });
60
+ // Convenience re-exports for existing codebases
61
+ export const { info, warn, error, debug, trace, fatal } = logger;
62
+ /**
63
+ * Changes the logging level of the current logger instance
64
+ * @param level The new log level to set
65
+ */
66
+ export function setLogLevel(level) {
67
+ logger.level = level;
68
+ debug(`Log level changed to ${level}`);
69
+ }
70
+ /**
71
+ * Helper function to measure and log execution time of async functions
72
+ * @param label Description of the operation being timed
73
+ * @param fn Function to execute and time
74
+ * @param level Log level to use for output (defaults to 'debug')
75
+ * @returns Result of the function execution
76
+ */
77
+ export async function timeIt(label, fn, level = 'debug') {
78
+ const start = process.hrtime.bigint();
79
+ try {
80
+ return await fn();
81
+ }
82
+ finally {
83
+ const end = process.hrtime.bigint();
84
+ const duration = Number(end - start) / 1_000_000; // Convert to milliseconds
85
+ switch (level) {
86
+ case 'trace':
87
+ logger.trace({ duration }, `${label} completed in ${duration.toFixed(2)}ms`);
88
+ break;
89
+ case 'debug':
90
+ logger.debug({ duration }, `${label} completed in ${duration.toFixed(2)}ms`);
91
+ break;
92
+ case 'info':
93
+ logger.info({ duration }, `${label} completed in ${duration.toFixed(2)}ms`);
94
+ break;
95
+ case 'warn':
96
+ logger.warn({ duration }, `${label} completed in ${duration.toFixed(2)}ms`);
97
+ break;
98
+ case 'error':
99
+ logger.error({ duration }, `${label} completed in ${duration.toFixed(2)}ms`);
100
+ break;
101
+ case 'fatal':
102
+ logger.fatal({ duration }, `${label} completed in ${duration.toFixed(2)}ms`);
103
+ break;
104
+ }
105
+ }
106
+ }
107
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"/","sources":["services/logger.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { pino } from 'pino';\nimport { XDGPaths } from '../utils/xdgPaths.js';\n\nconst logDir = XDGPaths.getAppLogDir('bktide');\nfs.mkdirSync(logDir, { recursive: true });\n\nconst logFile = path.join(logDir, 'cli.log');\n\nexport const logger = pino(\n {\n level: process.env.LOG_LEVEL || 'info',\n customLevels: {\n console: 80\n },\n transport: {\n targets: [\n // Direct console output (no pretty formatting)\n {\n target: 'pino-pretty',\n level: 'console',\n options: {\n colorize: false,\n useOnlyCustomProps: true,\n sync: true,\n minimumLevel: 'console',\n ignore: 'level,time,pid,hostname',\n errorProps: 'err,error,stack,message,code,details'\n }\n },\n // Debug output with pretty formatting\n {\n target: 'pino-pretty',\n level: 'trace',\n options: {\n colorize: true,\n sync: true,\n translateTime: 'HH:MM:ss.l',\n ignore: 'time,pid,hostname',\n errorProps: 'err,error,stack,message,code,details'\n }\n },\n // JSON file output for detailed logging\n {\n target: 'pino/file',\n level: 'trace',\n options: { \n destination: logFile,\n mkdir: true,\n sync: false \n }\n }\n ],\n dedupe: true\n },\n serializers: {\n err: pino.stdSerializers.err,\n error: pino.stdSerializers.err,\n stack: (stack: string) => stack,\n details: (details: any) => details\n }\n }\n);\n\n// Convenience re-exports for existing codebases\nexport const { info, warn, error, debug, trace, fatal } = logger;\n\n/**\n * Changes the logging level of the current logger instance\n * @param level The new log level to set\n */\nexport function setLogLevel(level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'console'): void {\n logger.level = level;\n debug(`Log level changed to ${level}`);\n}\n\n/**\n * Helper function to measure and log execution time of async functions\n * @param label Description of the operation being timed\n * @param fn Function to execute and time\n * @param level Log level to use for output (defaults to 'debug')\n * @returns Result of the function execution\n */\nexport async function timeIt<T>(\n label: string, \n fn: () => Promise<T>, \n level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' = 'debug'\n): Promise<T> {\n const start = process.hrtime.bigint();\n try {\n return await fn();\n } finally {\n const end = process.hrtime.bigint();\n const duration = Number(end - start) / 1_000_000; // Convert to milliseconds\n switch(level) {\n case 'trace': logger.trace({ duration }, `${label} completed in ${duration.toFixed(2)}ms`); break;\n case 'debug': logger.debug({ duration }, `${label} completed in ${duration.toFixed(2)}ms`); break;\n case 'info': logger.info({ duration }, `${label} completed in ${duration.toFixed(2)}ms`); break;\n case 'warn': logger.warn({ duration }, `${label} completed in ${duration.toFixed(2)}ms`); break;\n case 'error': logger.error({ duration }, `${label} completed in ${duration.toFixed(2)}ms`); break;\n case 'fatal': logger.fatal({ duration }, `${label} completed in ${duration.toFixed(2)}ms`); break;\n }\n }\n} "]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Common types for Buildkite GraphQL API
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=buildkite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildkite.js","sourceRoot":"/","sources":["types/buildkite.ts"],"names":[],"mappings":"AAAA;;GAEG","sourcesContent":["/**\n * Common types for Buildkite GraphQL API\n */\n\nexport interface PipelineNode {\n id: string;\n name: string;\n slug: string;\n description: string;\n url: string;\n repository: {\n url: string;\n };\n}\n\nexport interface BuildNode {\n id: string;\n number: number;\n url: string;\n state: string;\n message: string;\n commit: string;\n branch: string;\n createdAt: string;\n startedAt: string | null;\n finishedAt: string | null;\n}\n\nexport interface OrganizationNode {\n id: string;\n name: string;\n slug: string;\n}\n\nexport interface PageInfo {\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n startCursor: string;\n endCursor: string;\n} "]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"/","sources":["types/credentials.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Represents the validation status of a Buildkite API token\n */\nexport interface OrganizationValidationStatus {\n /** Whether the token is valid for the GraphQL API for this organization */\n graphql: boolean;\n /** Whether the token is valid for the REST API to access builds in this organization */\n builds: boolean;\n /** Whether the token is valid for the REST API to access organization details */\n organizations: boolean;\n}\n\nexport interface TokenValidationStatus {\n /** Combined status of all validation checks */\n valid: boolean;\n /** Whether the token can access the GraphQL API to list organizations */\n canListOrganizations: boolean;\n /** Validation status for each organization */\n organizations: Record<string, OrganizationValidationStatus>;\n}\n\n/**\n * Represents the complete status of a Buildkite API token\n */\nexport interface TokenStatus {\n /** Whether a token exists in the keychain */\n hasToken: boolean;\n /** Whether the token is valid for both GraphQL and REST APIs */\n isValid: boolean;\n /** Detailed validation status for each API */\n validation: TokenValidationStatus;\n}\n\n/**\n * Represents the result of checking a token's status\n */\nexport interface TokenCheckResult {\n /** The token status information */\n status: TokenStatus;\n /** Any errors encountered during validation */\n errors: unknown[];\n}\n\n/**\n * Represents the result of checking or storing a token\n */\nexport interface TokenCheckOrStoreResult {\n /** Whether a token was stored */\n stored: boolean;\n /** Any errors encountered during the process */\n errors: unknown[];\n}\n\n/**\n * Represents the result of storing a token\n */\nexport interface TokenStoreResult {\n /** Whether the token was successfully stored */\n success: boolean;\n /** Any errors encountered during storage */\n errors: unknown[];\n} "]}