@covibes/zeroshot 5.4.0 → 5.4.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 (136) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +8 -465
  3. package/cli/index.js +101 -5231
  4. package/package.json +16 -130
  5. package/CHANGELOG.md +0 -537
  6. package/cli/commands/providers.js +0 -149
  7. package/cli/lib/first-run.js +0 -211
  8. package/cli/lib/update-checker.js +0 -281
  9. package/cli/message-formatter-utils.js +0 -75
  10. package/cli/message-formatters-normal.js +0 -275
  11. package/cli/message-formatters-watch.js +0 -181
  12. package/cluster-templates/base-templates/debug-workflow.json +0 -375
  13. package/cluster-templates/base-templates/full-workflow.json +0 -581
  14. package/cluster-templates/base-templates/single-worker.json +0 -63
  15. package/cluster-templates/base-templates/worker-validator.json +0 -208
  16. package/cluster-templates/conductor-bootstrap.json +0 -124
  17. package/docker/zeroshot-cluster/Dockerfile +0 -152
  18. package/docker/zeroshot-cluster/pre-baked-deps.json +0 -28
  19. package/lib/completion.js +0 -174
  20. package/lib/docker-config.js +0 -220
  21. package/lib/git-remote-utils.js +0 -165
  22. package/lib/id-detector.js +0 -56
  23. package/lib/provider-defaults.js +0 -62
  24. package/lib/provider-detection.js +0 -59
  25. package/lib/provider-names.js +0 -57
  26. package/lib/settings/claude-auth.js +0 -78
  27. package/lib/settings.js +0 -503
  28. package/lib/stream-json-parser.js +0 -10
  29. package/scripts/fix-node-pty-permissions.js +0 -75
  30. package/scripts/record-demo.sh +0 -279
  31. package/scripts/setup-merge-queue.sh +0 -170
  32. package/scripts/test-install.sh +0 -40
  33. package/scripts/validate-templates.js +0 -100
  34. package/src/agent/agent-config.js +0 -246
  35. package/src/agent/agent-context-builder.js +0 -444
  36. package/src/agent/agent-hook-executor.js +0 -599
  37. package/src/agent/agent-lifecycle.js +0 -743
  38. package/src/agent/agent-stuck-detector.js +0 -256
  39. package/src/agent/agent-task-executor.js +0 -1690
  40. package/src/agent/agent-trigger-evaluator.js +0 -67
  41. package/src/agent/output-extraction.js +0 -217
  42. package/src/agent/output-reformatter.js +0 -175
  43. package/src/agent/schema-utils.js +0 -146
  44. package/src/agent-wrapper.js +0 -579
  45. package/src/agents/git-pusher-template.js +0 -285
  46. package/src/attach/attach-client.js +0 -438
  47. package/src/attach/attach-server.js +0 -543
  48. package/src/attach/index.js +0 -35
  49. package/src/attach/protocol.js +0 -220
  50. package/src/attach/ring-buffer.js +0 -121
  51. package/src/attach/socket-discovery.js +0 -267
  52. package/src/claude-task-runner.js +0 -574
  53. package/src/config-router.js +0 -80
  54. package/src/config-validator.js +0 -1925
  55. package/src/copy-worker.js +0 -43
  56. package/src/input-helpers.js +0 -65
  57. package/src/isolation-manager.js +0 -1471
  58. package/src/issue-providers/README.md +0 -305
  59. package/src/issue-providers/azure-devops-provider.js +0 -273
  60. package/src/issue-providers/base-provider.js +0 -232
  61. package/src/issue-providers/github-provider.js +0 -179
  62. package/src/issue-providers/gitlab-provider.js +0 -241
  63. package/src/issue-providers/index.js +0 -196
  64. package/src/issue-providers/jira-provider.js +0 -239
  65. package/src/ledger.js +0 -631
  66. package/src/lib/safe-exec.js +0 -88
  67. package/src/logic-engine.js +0 -223
  68. package/src/message-bus-bridge.js +0 -139
  69. package/src/message-bus.js +0 -249
  70. package/src/name-generator.js +0 -232
  71. package/src/orchestrator.js +0 -2815
  72. package/src/preflight.js +0 -639
  73. package/src/process-metrics.js +0 -608
  74. package/src/providers/anthropic/cli-builder.js +0 -73
  75. package/src/providers/anthropic/index.js +0 -204
  76. package/src/providers/anthropic/models.js +0 -23
  77. package/src/providers/anthropic/output-parser.js +0 -177
  78. package/src/providers/base-provider.js +0 -251
  79. package/src/providers/capabilities.js +0 -60
  80. package/src/providers/google/cli-builder.js +0 -55
  81. package/src/providers/google/index.js +0 -116
  82. package/src/providers/google/models.js +0 -24
  83. package/src/providers/google/output-parser.js +0 -101
  84. package/src/providers/index.js +0 -91
  85. package/src/providers/openai/cli-builder.js +0 -133
  86. package/src/providers/openai/index.js +0 -136
  87. package/src/providers/openai/models.js +0 -21
  88. package/src/providers/openai/output-parser.js +0 -143
  89. package/src/providers/opencode/cli-builder.js +0 -42
  90. package/src/providers/opencode/index.js +0 -103
  91. package/src/providers/opencode/models.js +0 -55
  92. package/src/providers/opencode/output-parser.js +0 -122
  93. package/src/schemas/sub-cluster.js +0 -185
  94. package/src/status-footer.js +0 -1026
  95. package/src/sub-cluster-wrapper.js +0 -601
  96. package/src/task-runner.js +0 -30
  97. package/src/template-resolver.js +0 -372
  98. package/src/tui/CHANGES.txt +0 -133
  99. package/src/tui/LAYOUT.md +0 -261
  100. package/src/tui/README.txt +0 -192
  101. package/src/tui/TWO-LEVEL-NAVIGATION.md +0 -186
  102. package/src/tui/data-poller.js +0 -349
  103. package/src/tui/demo.js +0 -208
  104. package/src/tui/formatters.js +0 -129
  105. package/src/tui/index.js +0 -193
  106. package/src/tui/keybindings.js +0 -324
  107. package/src/tui/layout.js +0 -334
  108. package/src/tui/renderer.js +0 -184
  109. package/task-lib/attachable-watcher.js +0 -309
  110. package/task-lib/claude-recovery.js +0 -156
  111. package/task-lib/commands/clean.js +0 -50
  112. package/task-lib/commands/episodes.js +0 -105
  113. package/task-lib/commands/get-log-path.js +0 -23
  114. package/task-lib/commands/kill.js +0 -32
  115. package/task-lib/commands/list.js +0 -105
  116. package/task-lib/commands/logs.js +0 -453
  117. package/task-lib/commands/resume.js +0 -42
  118. package/task-lib/commands/run.js +0 -57
  119. package/task-lib/commands/schedule.js +0 -105
  120. package/task-lib/commands/scheduler-cmd.js +0 -96
  121. package/task-lib/commands/schedules.js +0 -148
  122. package/task-lib/commands/status.js +0 -44
  123. package/task-lib/commands/unschedule.js +0 -16
  124. package/task-lib/completion.js +0 -9
  125. package/task-lib/config.js +0 -8
  126. package/task-lib/name-generator.js +0 -230
  127. package/task-lib/package.json +0 -3
  128. package/task-lib/runner.js +0 -201
  129. package/task-lib/scheduler.js +0 -252
  130. package/task-lib/store.js +0 -529
  131. package/task-lib/tui/formatters.js +0 -215
  132. package/task-lib/tui/index.js +0 -197
  133. package/task-lib/tui/layout.js +0 -111
  134. package/task-lib/tui/renderer.js +0 -129
  135. package/task-lib/tui.js +0 -425
  136. package/task-lib/watcher.js +0 -226
@@ -1,232 +0,0 @@
1
- /**
2
- * Base Provider - Abstract base class for issue providers
3
- *
4
- * This class represents a "platform" that can:
5
- * 1. Fetch issues (all providers)
6
- * 2. Create PRs/MRs (git-hosting providers only: GitHub, GitLab, Azure DevOps)
7
- *
8
- * Defines interface for fetching issues from different sources (GitHub, GitLab, Jira, etc)
9
- * Each provider must implement:
10
- * - Static properties: id, displayName
11
- * - Static methods: detectIdentifier(), getRequiredTool()
12
- * - Instance method: fetchIssue()
13
- *
14
- * Git-hosting providers should also implement:
15
- * - Static method: supportsPR() returning true
16
- * - Static method: getPRTool() for PR/MR CLI tool info
17
- */
18
-
19
- class IssueProvider {
20
- /**
21
- * Provider identifier (e.g., 'github', 'gitlab')
22
- * @type {string}
23
- */
24
- static id = null;
25
-
26
- /**
27
- * Human-readable provider name
28
- * @type {string}
29
- */
30
- static displayName = null;
31
-
32
- /**
33
- * Whether this provider supports PR/MR creation.
34
- * Override in subclass to return true for git-hosting platforms.
35
- * @returns {boolean}
36
- */
37
- static supportsPR() {
38
- return false;
39
- }
40
-
41
- /**
42
- * Get PR/MR CLI tool info for preflight checks.
43
- * Only git-hosting providers (GitHub, GitLab, Azure DevOps) implement this.
44
- * @returns {{ name: string, checkCmd: string, installHint: string, displayName: string }|null}
45
- */
46
- static getPRTool() {
47
- return null;
48
- }
49
-
50
- /**
51
- * Detect if input matches this provider's patterns
52
- * @param {string} _input - User input (URL, issue key, number)
53
- * @param {Object} _settings - User settings from settings.js
54
- * @param {Object|null} _gitContext - Auto-detected git remote context
55
- * @returns {boolean}
56
- */
57
- static detectIdentifier(_input, _settings, _gitContext) {
58
- throw new Error(`${this.name}.detectIdentifier() must be implemented by subclass`);
59
- }
60
-
61
- /**
62
- * Shared detection logic for bare numbers (e.g., "123").
63
- * Implements the priority cascade:
64
- * 1. Git context (highest priority) - auto-detected from git remote
65
- * 2. Settings (defaultIssueSource)
66
- * 3. Legacy fallback (GitHub only, for backward compatibility)
67
- *
68
- * Call this from subclass detectIdentifier() for bare number handling.
69
- *
70
- * @param {string} input - User input to check
71
- * @param {Object} settings - User settings
72
- * @param {Object|null} gitContext - Git context from detectGitContext()
73
- * @param {string} providerId - This provider's ID (e.g., 'github', 'gitlab')
74
- * @param {Object} [options] - Additional options
75
- * @param {boolean} [options.requiresAdditionalSettings] - If true, check additional settings exist
76
- * @param {string[]} [options.requiredSettings] - Settings keys that must exist for this provider
77
- * @returns {boolean} True if this provider should handle the bare number
78
- */
79
- static detectBareNumber(input, settings, gitContext, providerId, options = {}) {
80
- // Only handle bare numbers
81
- if (!/^\d+$/.test(input)) {
82
- return false;
83
- }
84
-
85
- // 1. Git context takes highest priority
86
- if (gitContext?.provider) {
87
- return gitContext.provider === providerId;
88
- }
89
-
90
- // 2. Check settings.defaultIssueSource
91
- if (settings.defaultIssueSource) {
92
- if (settings.defaultIssueSource !== providerId) {
93
- return false;
94
- }
95
- // If provider requires additional settings, validate them
96
- if (options.requiredSettings?.length > 0) {
97
- return options.requiredSettings.every((key) => settings[key]);
98
- }
99
- return true;
100
- }
101
-
102
- // 3. Legacy fallback - only GitHub gets the fallback for backward compatibility
103
- return providerId === 'github';
104
- }
105
-
106
- /**
107
- * Shared detection logic for org/repo#123 format.
108
- * Some providers (GitHub, GitLab) use this format.
109
- *
110
- * @param {string} input - User input to check
111
- * @param {Object} settings - User settings
112
- * @param {Object|null} gitContext - Git context
113
- * @param {string} providerId - This provider's ID
114
- * @returns {boolean} True if this provider should handle the input
115
- */
116
- static detectRepoIssueFormat(input, settings, gitContext, providerId) {
117
- // Match org/repo#123 format
118
- if (!/^[\w.-]+\/[\w.-]+#\d+$/.test(input)) {
119
- return false;
120
- }
121
-
122
- // 1. Git context takes priority
123
- if (gitContext?.provider) {
124
- return gitContext.provider === providerId;
125
- }
126
-
127
- // 2. Settings fallback
128
- return settings.defaultIssueSource === providerId;
129
- }
130
-
131
- /**
132
- * Get required CLI tool info
133
- * @returns {{ name: string, checkCmd: string, installHint: string }}
134
- */
135
- static getRequiredTool() {
136
- throw new Error(`${this.name}.getRequiredTool() must be implemented by subclass`);
137
- }
138
-
139
- /**
140
- * Check if the provider's CLI is authenticated.
141
- * Override in subclass to implement provider-specific auth checks.
142
- *
143
- * @param {string|null} hostname - Optional hostname for providers with multi-instance support
144
- * (e.g., GitLab with gitlab.com + self-hosted). When provided, only check auth for that
145
- * specific instance to avoid false failures from other unconfigured instances.
146
- * @returns {{ authenticated: boolean, error: string|null, recovery: string[] }}
147
- * - authenticated: true if auth is valid
148
- * - error: error message if not authenticated, null otherwise
149
- * - recovery: array of steps to fix auth issues
150
- */
151
- static checkAuth(_hostname = null) {
152
- // Default: no auth check required (some CLIs like jira use config files)
153
- return { authenticated: true, error: null, recovery: [] };
154
- }
155
-
156
- /**
157
- * Get settings schema for this provider.
158
- * Override in subclass to define provider-specific settings.
159
- *
160
- * Schema format:
161
- * {
162
- * settingKey: {
163
- * type: 'string' | 'number' | 'boolean',
164
- * nullable: true | false,
165
- * default: <default value>,
166
- * description: 'Human-readable description',
167
- * pattern?: RegExp, // Optional validation pattern
168
- * patternMsg?: string // Error message if pattern fails
169
- * }
170
- * }
171
- *
172
- * @returns {Object.<string, Object>} Settings schema
173
- */
174
- static getSettingsSchema() {
175
- return {};
176
- }
177
-
178
- /**
179
- * Validate a setting value for this provider.
180
- * Uses schema from getSettingsSchema() by default.
181
- *
182
- * @param {string} key - Setting key
183
- * @param {any} value - Setting value
184
- * @returns {string|null|undefined} Error message if invalid, null if valid, undefined if not this provider's setting
185
- */
186
- static validateSetting(key, value) {
187
- const schema = this.getSettingsSchema();
188
- const config = schema[key];
189
-
190
- if (!config) {
191
- return undefined; // Not this provider's setting
192
- }
193
-
194
- // Nullable check
195
- if (config.nullable && value === null) {
196
- return null; // null is valid
197
- }
198
-
199
- // Type validation
200
- if (config.type === 'string' && typeof value !== 'string') {
201
- return `${key} must be a string${config.nullable ? ' or null' : ''}`;
202
- }
203
-
204
- // Pattern validation
205
- if (config.pattern && typeof value === 'string' && !config.pattern.test(value)) {
206
- return config.patternMsg || `${key} has invalid format`;
207
- }
208
-
209
- return null; // Valid
210
- }
211
-
212
- /**
213
- * Fetch issue from provider
214
- * @param {string} _identifier - Issue identifier (URL, key, number)
215
- * @param {Object} _settings - User settings from settings.js
216
- * @returns {Promise<Object>} InputData object with structure:
217
- * {
218
- * number: Number|null,
219
- * title: String,
220
- * body: String,
221
- * labels: Array<{name: String}>,
222
- * comments: Array<{author, createdAt, body}>,
223
- * url: String|null,
224
- * context: String // Formatted markdown
225
- * }
226
- */
227
- fetchIssue(_identifier, _settings) {
228
- throw new Error(`${this.constructor.name}.fetchIssue() must be implemented by subclass`);
229
- }
230
- }
231
-
232
- module.exports = IssueProvider;
@@ -1,179 +0,0 @@
1
- /**
2
- * GitHub Provider - Fetch issues from GitHub via gh CLI
3
- */
4
-
5
- const IssueProvider = require('./base-provider');
6
- const { execSync } = require('../lib/safe-exec');
7
-
8
- class GitHubProvider extends IssueProvider {
9
- static id = 'github';
10
- static displayName = 'GitHub';
11
-
12
- /**
13
- * GitHub supports PR creation via gh CLI
14
- */
15
- static supportsPR() {
16
- return true;
17
- }
18
-
19
- /**
20
- * Get PR CLI tool info for preflight checks
21
- */
22
- static getPRTool() {
23
- return {
24
- name: 'gh',
25
- checkCmd: 'gh --version',
26
- installHint: 'https://cli.github.com/',
27
- displayName: 'GitHub',
28
- };
29
- }
30
-
31
- /**
32
- * Detect GitHub URLs and issue references
33
- * Matches:
34
- * - github.com URLs
35
- * - org/repo#123 format
36
- * - Bare numbers when git remote is GitHub (auto-detected)
37
- * - Bare numbers when defaultIssueSource=github
38
- *
39
- * @param {string} input - Issue identifier (URL, number, or org/repo#123)
40
- * @param {Object} settings - User settings
41
- * @param {Object|null} gitContext - Auto-detected git remote context
42
- * @returns {boolean} True if this provider should handle the input
43
- */
44
- static detectIdentifier(input, settings, gitContext = null) {
45
- // GitHub URLs
46
- if (input.includes('github.com') && /\/issues\/\d+/.test(input)) {
47
- return true;
48
- }
49
-
50
- // org/repo#123 format - use shared logic
51
- if (IssueProvider.detectRepoIssueFormat(input, settings, gitContext, 'github')) {
52
- return true;
53
- }
54
-
55
- // Bare numbers - use shared priority cascade logic
56
- return IssueProvider.detectBareNumber(input, settings, gitContext, 'github');
57
- }
58
-
59
- static getRequiredTool() {
60
- return {
61
- name: 'gh',
62
- checkCmd: 'gh --version',
63
- installHint: 'Install gh CLI: https://cli.github.com/',
64
- };
65
- }
66
-
67
- /**
68
- * Check gh CLI authentication
69
- */
70
- static checkAuth() {
71
- try {
72
- execSync('gh auth status', { encoding: 'utf8', stdio: 'pipe' });
73
- return { authenticated: true, error: null, recovery: [] };
74
- } catch (err) {
75
- const stderr = err.stderr || err.message || '';
76
-
77
- if (stderr.includes('not logged in')) {
78
- return {
79
- authenticated: false,
80
- error: 'gh CLI not authenticated',
81
- recovery: [
82
- 'Run: gh auth login',
83
- 'Select GitHub.com, HTTPS, and authenticate via browser',
84
- 'Then verify: gh auth status',
85
- ],
86
- };
87
- }
88
-
89
- return {
90
- authenticated: false,
91
- error: stderr.trim() || 'Unknown gh auth error',
92
- recovery: ['Run: gh auth login', 'Then verify: gh auth status'],
93
- };
94
- }
95
- }
96
-
97
- /**
98
- * GitHub-specific settings schema
99
- * GitHub has no extra settings (cloud-only, no self-hosted config needed)
100
- */
101
- static getSettingsSchema() {
102
- return {};
103
- }
104
-
105
- fetchIssue(identifier, _settings) {
106
- try {
107
- const issueNumber = this._extractIssueNumber(identifier);
108
-
109
- // Fetch issue using gh CLI
110
- const cmd = `gh issue view ${issueNumber} --json number,title,body,labels,assignees,comments,url`;
111
- const output = execSync(cmd, { encoding: 'utf8' });
112
- const issue = JSON.parse(output);
113
-
114
- return this._parseIssue(issue);
115
- } catch (error) {
116
- throw new Error(`Failed to fetch GitHub issue: ${error.message}`);
117
- }
118
- }
119
-
120
- /**
121
- * Extract issue number from URL or return as-is
122
- * @private
123
- */
124
- _extractIssueNumber(issueRef) {
125
- // If it's a URL, extract the number
126
- const urlMatch = issueRef.match(/\/issues\/(\d+)/);
127
- if (urlMatch) {
128
- return urlMatch[1];
129
- }
130
-
131
- // org/repo#123 format
132
- const repoMatch = issueRef.match(/^[\w-]+\/[\w-]+#(\d+)$/);
133
- if (repoMatch) {
134
- return repoMatch[1];
135
- }
136
-
137
- // Otherwise assume it's already a number
138
- return issueRef;
139
- }
140
-
141
- /**
142
- * Parse issue into standardized InputData format
143
- * @private
144
- */
145
- _parseIssue(issue) {
146
- let context = `# GitHub Issue #${issue.number}\n\n`;
147
- context += `## Title\n${issue.title}\n\n`;
148
-
149
- if (issue.body) {
150
- context += `## Description\n${issue.body}\n\n`;
151
- }
152
-
153
- if (issue.labels && issue.labels.length > 0) {
154
- context += `## Labels\n`;
155
- context += issue.labels.map((l) => `- ${l.name}`).join('\n');
156
- context += '\n\n';
157
- }
158
-
159
- if (issue.comments && issue.comments.length > 0) {
160
- context += `## Comments\n\n`;
161
- for (const comment of issue.comments) {
162
- context += `### ${comment.author.login} (${new Date(comment.createdAt).toISOString()})\n`;
163
- context += `${comment.body}\n\n`;
164
- }
165
- }
166
-
167
- return {
168
- number: issue.number,
169
- title: issue.title,
170
- body: issue.body,
171
- labels: issue.labels || [],
172
- comments: issue.comments || [],
173
- url: issue.url || null,
174
- context,
175
- };
176
- }
177
- }
178
-
179
- module.exports = GitHubProvider;
@@ -1,241 +0,0 @@
1
- /**
2
- * GitLab Provider - Fetch issues from GitLab via glab CLI
3
- * Supports both cloud (gitlab.com) and self-hosted instances
4
- */
5
-
6
- const IssueProvider = require('./base-provider');
7
- const { execSync } = require('../lib/safe-exec');
8
-
9
- class GitLabProvider extends IssueProvider {
10
- static id = 'gitlab';
11
- static displayName = 'GitLab';
12
-
13
- /**
14
- * GitLab supports MR creation via glab CLI
15
- */
16
- static supportsPR() {
17
- return true;
18
- }
19
-
20
- /**
21
- * Get MR CLI tool info for preflight checks
22
- */
23
- static getPRTool() {
24
- return {
25
- name: 'glab',
26
- checkCmd: 'glab --version',
27
- installHint: 'brew install glab (or https://gitlab.com/gitlab-org/cli)',
28
- displayName: 'GitLab',
29
- };
30
- }
31
-
32
- /**
33
- * Detect GitLab URLs and issue references
34
- * Matches:
35
- * - gitlab.com URLs
36
- * - Self-hosted GitLab URLs (via gitlabInstance setting)
37
- * - org/repo#123 when git remote is GitLab (auto-detected)
38
- * - org/repo#123 when defaultIssueSource=gitlab
39
- * - Bare numbers when git remote is GitLab (auto-detected)
40
- * - Bare numbers when defaultIssueSource=gitlab
41
- *
42
- * @param {string} input - Issue identifier (URL, number, or org/repo#123)
43
- * @param {Object} settings - User settings
44
- * @param {Object|null} gitContext - Auto-detected git remote context
45
- * @returns {boolean} True if this provider should handle the input
46
- */
47
- static detectIdentifier(input, settings, gitContext = null) {
48
- // GitLab cloud URLs
49
- if (input.includes('gitlab.com') && /\/-\/issues\/\d+/.test(input)) {
50
- return true;
51
- }
52
-
53
- // Self-hosted GitLab URLs
54
- if (
55
- settings.gitlabInstance &&
56
- input.includes(settings.gitlabInstance) &&
57
- /\/-\/issues\/\d+/.test(input)
58
- ) {
59
- return true;
60
- }
61
-
62
- // org/repo#123 format - use shared logic
63
- if (IssueProvider.detectRepoIssueFormat(input, settings, gitContext, 'gitlab')) {
64
- return true;
65
- }
66
-
67
- // Bare numbers - use shared priority cascade logic
68
- return IssueProvider.detectBareNumber(input, settings, gitContext, 'gitlab');
69
- }
70
-
71
- static getRequiredTool() {
72
- return {
73
- name: 'glab',
74
- checkCmd: 'glab --version',
75
- installHint: 'Install glab CLI: brew install glab (or https://gitlab.com/gitlab-org/cli)',
76
- };
77
- }
78
-
79
- /**
80
- * Check glab CLI authentication for a specific hostname.
81
- * If hostname is provided, only checks that specific instance.
82
- * Otherwise, uses glab's default context detection (git remote).
83
- *
84
- * @param {string|null} hostname - GitLab hostname to check (e.g., 'gitlab.com', 'gitlab.lrz.de')
85
- */
86
- static checkAuth(hostname = null) {
87
- // Use --hostname flag to check specific instance, avoiding false failures
88
- // when other configured instances are unauthenticated
89
- const cmd = hostname ? `glab auth status --hostname ${hostname}` : 'glab auth status';
90
-
91
- try {
92
- execSync(cmd, { encoding: 'utf8', stdio: 'pipe' });
93
- return { authenticated: true, error: null, recovery: [] };
94
- } catch (err) {
95
- const stderr = err.stderr || err.message || '';
96
-
97
- const hostnameHint = hostname || 'your GitLab instance';
98
- if (
99
- stderr.includes('not logged in') ||
100
- stderr.includes('no authentication') ||
101
- stderr.includes('No token found')
102
- ) {
103
- return {
104
- authenticated: false,
105
- error: `glab CLI not authenticated for ${hostnameHint}`,
106
- recovery: [
107
- hostname ? `Run: glab auth login --hostname ${hostname}` : 'Run: glab auth login',
108
- 'Authenticate via browser when prompted',
109
- `Then verify: glab auth status${hostname ? ` --hostname ${hostname}` : ''}`,
110
- ],
111
- };
112
- }
113
-
114
- return {
115
- authenticated: false,
116
- error: stderr.trim() || 'Unknown glab auth error',
117
- recovery: [
118
- hostname ? `Run: glab auth login --hostname ${hostname}` : 'Run: glab auth login',
119
- 'Then verify: glab auth status',
120
- ],
121
- };
122
- }
123
- }
124
-
125
- /**
126
- * GitLab-specific settings schema
127
- */
128
- static getSettingsSchema() {
129
- return {
130
- gitlabInstance: {
131
- type: 'string',
132
- nullable: true,
133
- default: null,
134
- description: "Self-hosted GitLab URL (e.g., 'gitlab.company.com')",
135
- },
136
- };
137
- }
138
-
139
- fetchIssue(identifier, _settings) {
140
- try {
141
- // glab accepts full URLs directly - use that for simplicity
142
- const isUrl = /^https?:\/\//.test(identifier);
143
- let cmd;
144
-
145
- if (isUrl) {
146
- // Pass URL directly to glab - handles self-hosted instances automatically
147
- cmd = `glab issue view "${identifier}" --output json`;
148
- } else {
149
- // For org/repo#123 or bare numbers, parse and build command
150
- const { issueNumber, repo } = this._parseIdentifier(identifier);
151
- cmd = `glab issue view ${issueNumber} --output json`;
152
- if (repo) {
153
- cmd += ` --repo ${repo}`;
154
- }
155
- }
156
-
157
- const output = execSync(cmd, { encoding: 'utf8' });
158
- const issue = JSON.parse(output);
159
-
160
- return this._parseIssue(issue);
161
- } catch (error) {
162
- throw new Error(`Failed to fetch GitLab issue: ${error.message}`);
163
- }
164
- }
165
-
166
- /**
167
- * Parse identifier to extract issue number, repo, and hostname
168
- * @private
169
- */
170
- _parseIdentifier(identifier) {
171
- // URL format: https://gitlab.example.com/org/repo/-/issues/123
172
- const urlMatch = identifier.match(/https?:\/\/([^/]+)\/([^/]+\/[^/]+)\/-\/issues\/(\d+)/);
173
- if (urlMatch) {
174
- const hostname = urlMatch[1];
175
- return {
176
- hostname: hostname !== 'gitlab.com' ? hostname : null,
177
- repo: urlMatch[2],
178
- issueNumber: urlMatch[3],
179
- };
180
- }
181
-
182
- // org/repo#123 format
183
- const repoMatch = identifier.match(/^([\w-]+\/[\w-]+)#(\d+)$/);
184
- if (repoMatch) {
185
- return { hostname: null, repo: repoMatch[1], issueNumber: repoMatch[2] };
186
- }
187
-
188
- // Bare number (relies on glab's default repo)
189
- return { hostname: null, repo: null, issueNumber: identifier };
190
- }
191
-
192
- /**
193
- * Parse GitLab issue into standardized InputData format
194
- * @private
195
- */
196
- _parseIssue(issue) {
197
- let context = `# GitLab Issue #${issue.iid || issue.id}\n\n`;
198
- context += `## Title\n${issue.title}\n\n`;
199
-
200
- if (issue.description) {
201
- context += `## Description\n${issue.description}\n\n`;
202
- }
203
-
204
- if (issue.labels && issue.labels.length > 0) {
205
- context += `## Labels\n`;
206
- context += issue.labels.map((l) => `- ${l}`).join('\n');
207
- context += '\n\n';
208
- }
209
-
210
- if (issue.notes && issue.notes.length > 0) {
211
- context += `## Comments\n\n`;
212
- for (const note of issue.notes) {
213
- const author = note.author?.username || 'unknown';
214
- context += `### ${author} (${note.created_at})\n`;
215
- context += `${note.body}\n\n`;
216
- }
217
- }
218
-
219
- // Map GitLab labels to GitHub format
220
- const labels = (issue.labels || []).map((name) => ({ name }));
221
-
222
- // Map GitLab notes to GitHub comment format
223
- const comments = (issue.notes || []).map((note) => ({
224
- author: { login: note.author?.username || 'unknown' },
225
- createdAt: note.created_at,
226
- body: note.body,
227
- }));
228
-
229
- return {
230
- number: issue.iid || issue.id || null,
231
- title: issue.title,
232
- body: issue.description || '',
233
- labels,
234
- comments,
235
- url: issue.web_url || null,
236
- context,
237
- };
238
- }
239
- }
240
-
241
- module.exports = GitLabProvider;