@happyvertical/repos 0.74.8

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.
package/AGENT.md ADDED
@@ -0,0 +1,33 @@
1
+ # @happyvertical/repos
2
+
3
+ <!-- BEGIN AGENT:GENERATED -->
4
+ ## Purpose
5
+ Standardized repository interface for GitHub, GitLab, Bitbucket, and Azure DevOps
6
+
7
+ ## Package Map
8
+ - Package: `@happyvertical/repos`
9
+ - Hierarchy path: `@happyvertical/sdk > packages > repos`
10
+ - Workspace position: `22 of 30` local packages
11
+ - Internal dependencies: `@happyvertical/graphql`
12
+ - Internal dependents: `@happyvertical/github-actions`, `@happyvertical/projects`
13
+ - Knowledge graph files: `AGENT.md`, `metadata.json`, `ecosystem-manifest.json`
14
+
15
+ ## Build & Test
16
+ ```bash
17
+ pnpm --filter @happyvertical/repos build
18
+ pnpm --filter @happyvertical/repos test
19
+ pnpm --filter @happyvertical/repos clean
20
+ ```
21
+
22
+ ## Agent Correction Loops
23
+ - If module resolution or export errors mention a workspace dependency, build the dependency first (`pnpm --filter @happyvertical/graphql build`) and then rerun `pnpm --filter @happyvertical/repos build`.
24
+ - If tests or exports fail after API, type, or bundle changes, run `pnpm --filter @happyvertical/repos clean` followed by `pnpm --filter @happyvertical/repos build` and `pnpm --filter @happyvertical/repos test`.
25
+ - If failures span multiple packages or Turborepo ordering looks wrong, run `pnpm build` and `pnpm typecheck` from the repo root before retrying package-scoped commands.
26
+
27
+ ## Ecosystem Relationships
28
+ - Provides: Standardized repository interface for GitHub, GitLab, Bitbucket, and Azure DevOps
29
+ - Implements: none
30
+ - Requires: @happyvertical/graphql, js-yaml
31
+ - Stability: stable (Primary package surface is described as implemented and production-oriented.)
32
+ <!-- END AGENT:GENERATED -->
33
+
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright <2025> <Happy Vertical Corporation>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # @happyvertical/repos
2
+
3
+ Standardized repository interface for GitHub, GitLab, Bitbucket, and Azure DevOps.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @happyvertical/repos
9
+ ```
10
+
11
+ ## Claude Code Context
12
+
13
+ Install Claude Code context files for AI-assisted development:
14
+
15
+ ```bash
16
+ npx have-repos-context
17
+ ```
18
+
19
+ This copies the package's `AGENT.md` documentation and `metadata.json` metadata to your project's `.claude/` directory, enabling Claude to provide better assistance when working with this package.
20
+
21
+ ## Usage
22
+
23
+ ```typescript
24
+ import { getRepository } from '@happyvertical/repos';
25
+
26
+ // Create a GitHub repository client
27
+ const repo = await getRepository({
28
+ type: 'github',
29
+ owner: 'happyvertical',
30
+ repo: 'sdk',
31
+ token: process.env.GITHUB_TOKEN
32
+ });
33
+
34
+ // Get issue
35
+ const issue = await repo.getIssue(352);
36
+
37
+ // Add labels
38
+ await repo.addLabels(352, ['type: feature', 'priority: high', 'size: xl']);
39
+
40
+ // Post comment
41
+ await repo.addComment(352, '## 🤖 AI Triage\n\n**Type**: feature...');
42
+
43
+ // Search for duplicates
44
+ const duplicates = await repo.searchIssues('kanban automation', {
45
+ state: 'open',
46
+ labels: ['type: feature'],
47
+ });
48
+ ```
49
+
50
+ ## Features
51
+
52
+ - **Platform-agnostic**: Works with GitHub, GitLab, Bitbucket, Azure DevOps
53
+ - **Type-safe**: Full TypeScript support
54
+ - **Consistent API**: Same interface across all platforms
55
+ - **Factory pattern**: Simple `getRepository()` function
56
+ - **Comprehensive**: Issues, PRs, labels, comments, assignments, search
57
+
58
+ ## API
59
+
60
+ ### Issues
61
+
62
+ - `getIssue(number)` - Get issue details
63
+ - `createIssue(data)` - Create new issue
64
+ - `updateIssue(number, data)` - Update issue
65
+ - `closeIssue(number)` - Close issue
66
+
67
+ ### Labels
68
+
69
+ - `addLabels(issueNumber, labels)` - Add labels to issue
70
+ - `removeLabel(issueNumber, label)` - Remove label from issue
71
+ - `createLabel(label)` - Create repository label
72
+ - `updateLabel(name, label)` - Update existing label
73
+ - `listLabels()` - List all repository labels
74
+
75
+ ### Comments
76
+
77
+ - `addComment(issueNumber, body)` - Add comment to issue
78
+ - `updateComment(commentId, body)` - Update existing comment
79
+ - `deleteComment(commentId)` - Delete comment
80
+ - `listComments(issueNumber)` - List all comments on issue
81
+
82
+ ### Assignments
83
+
84
+ - `assignIssue(issueNumber, assignees)` - Assign users to issue
85
+ - `unassignIssue(issueNumber, assignees)` - Unassign users from issue
86
+
87
+ ### Pull Requests
88
+
89
+ - `getPullRequest(number)` - Get PR details
90
+ - `createPullRequest(data)` - Create new PR
91
+ - `mergePullRequest(number, method)` - Merge PR
92
+
93
+ ### Search
94
+
95
+ - `searchIssues(query, filters)` - Search issues with filters
96
+
97
+ ### Node IDs (for Projects V2)
98
+
99
+ - `getIssueNodeId(issueNumber)` - Get GraphQL node ID for issue
100
+ - `getPRNodeId(prNumber)` - Get GraphQL node ID for PR
101
+
102
+ ## Supported Platforms
103
+
104
+ - ✅ **GitHub** - Full support
105
+ - ⏳ **GitLab** - Coming soon
106
+ - ⏳ **Bitbucket** - Coming soon
107
+ - ⏳ **Azure DevOps** - Coming soon
108
+
109
+ ## License
110
+
111
+ MIT
@@ -0,0 +1 @@
1
+ export { }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=claude-context.d.ts.map
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, mkdirSync, copyFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ const Dirname = dirname(fileURLToPath(import.meta.url));
6
+ const pkgRoot = join(Dirname, "../..");
7
+ const targetDir = join(process.cwd(), ".claude");
8
+ if (!existsSync(targetDir)) {
9
+ mkdirSync(targetDir, { recursive: true });
10
+ }
11
+ const pkgName = "repos";
12
+ const agentMdSrc = existsSync(join(pkgRoot, "AGENT.md")) ? join(pkgRoot, "AGENT.md") : join(pkgRoot, "CLAUDE.md");
13
+ const metaSrc = existsSync(join(pkgRoot, "metadata.json")) ? join(pkgRoot, "metadata.json") : join(pkgRoot, ".claude-meta.json");
14
+ if (existsSync(agentMdSrc)) {
15
+ copyFileSync(agentMdSrc, join(targetDir, `have-${pkgName}.md`));
16
+ }
17
+ if (existsSync(metaSrc)) {
18
+ copyFileSync(metaSrc, join(targetDir, `have-${pkgName}.meta.json`));
19
+ }
20
+ console.log(`✓ Installed @happyvertical/${pkgName} context to .claude/`);
21
+ //# sourceMappingURL=claude-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-context.js","sources":["../../src/cli/claude-context.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI script to install agent context for @happyvertical/repos\n * Run the published context installer binary for this package.\n */\nimport { copyFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst Dirname = dirname(fileURLToPath(import.meta.url));\nconst pkgRoot = join(Dirname, '../..');\nconst targetDir = join(process.cwd(), '.claude');\n\nif (!existsSync(targetDir)) {\n mkdirSync(targetDir, { recursive: true });\n}\n\nconst pkgName = 'repos';\nconst agentMdSrc = existsSync(join(pkgRoot, 'AGENT.md'))\n ? join(pkgRoot, 'AGENT.md')\n : join(pkgRoot, 'CLAUDE.md');\nconst metaSrc = existsSync(join(pkgRoot, 'metadata.json'))\n ? join(pkgRoot, 'metadata.json')\n : join(pkgRoot, '.claude-meta.json');\n\nif (existsSync(agentMdSrc)) {\n copyFileSync(agentMdSrc, join(targetDir, `have-${pkgName}.md`));\n}\n\nif (existsSync(metaSrc)) {\n copyFileSync(metaSrc, join(targetDir, `have-${pkgName}.meta.json`));\n}\n\nconsole.log(`✓ Installed @happyvertical/${pkgName} context to .claude/`);\n"],"names":[],"mappings":";;;;AASA,MAAM,UAAU,QAAQ,cAAc,YAAY,GAAG,CAAC;AACtD,MAAM,UAAU,KAAK,SAAS,OAAO;AACrC,MAAM,YAAY,KAAK,QAAQ,IAAA,GAAO,SAAS;AAE/C,IAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,YAAU,WAAW,EAAE,WAAW,KAAA,CAAM;AAC1C;AAEA,MAAM,UAAU;AAChB,MAAM,aAAa,WAAW,KAAK,SAAS,UAAU,CAAC,IACnD,KAAK,SAAS,UAAU,IACxB,KAAK,SAAS,WAAW;AAC7B,MAAM,UAAU,WAAW,KAAK,SAAS,eAAe,CAAC,IACrD,KAAK,SAAS,eAAe,IAC7B,KAAK,SAAS,mBAAmB;AAErC,IAAI,WAAW,UAAU,GAAG;AAC1B,eAAa,YAAY,KAAK,WAAW,QAAQ,OAAO,KAAK,CAAC;AAChE;AAEA,IAAI,WAAW,OAAO,GAAG;AACvB,eAAa,SAAS,KAAK,WAAW,QAAQ,OAAO,YAAY,CAAC;AACpE;AAEA,QAAQ,IAAI,8BAA8B,OAAO,sBAAsB;"}
@@ -0,0 +1,453 @@
1
+ export declare interface Branch {
2
+ name: string;
3
+ sha: string;
4
+ protected: boolean;
5
+ }
6
+
7
+ declare interface Comment_2 {
8
+ id: string;
9
+ body: string;
10
+ author: User;
11
+ createdAt: Date;
12
+ updatedAt: Date;
13
+ url: string;
14
+ }
15
+ export { Comment_2 as Comment }
16
+
17
+ /**
18
+ * Options for creating a repository from a template
19
+ */
20
+ export declare interface CreateFromTemplateOptions {
21
+ /** The organization or user who will own the new repository */
22
+ owner: string;
23
+ /** The name for the new repository */
24
+ name: string;
25
+ /** A short description of the new repository */
26
+ description?: string;
27
+ /** Whether the new repository should be private (default: true) */
28
+ isPrivate?: boolean;
29
+ /** Whether to include all branches from the template (default: false, only default branch) */
30
+ includeAllBranches?: boolean;
31
+ }
32
+
33
+ export declare interface CreateIssueInput {
34
+ title: string;
35
+ body?: string;
36
+ labels?: string[];
37
+ assignees?: string[];
38
+ }
39
+
40
+ export declare interface CreatePRInput {
41
+ title: string;
42
+ body?: string;
43
+ headRef: string;
44
+ baseRef: string;
45
+ draft?: boolean;
46
+ }
47
+
48
+ /**
49
+ * Detect which template an issue was created from based on labels
50
+ *
51
+ * Matches issue labels against template labels to find the best match.
52
+ * Returns the template with the most matching labels.
53
+ *
54
+ * @param labels - Issue labels
55
+ * @param templates - Available templates
56
+ * @returns Matching template or undefined if no match
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * const templates = await fetchIssueTemplates(repo);
61
+ * const template = detectTemplateFromLabels(['bug', 'critical'], templates);
62
+ * if (template) {
63
+ * const fields = parseIssueBody(issue.body, template);
64
+ * }
65
+ * ```
66
+ */
67
+ export declare function detectTemplateFromLabels(labels: string[], templates: IssueTemplate[]): IssueTemplate | undefined;
68
+
69
+ /**
70
+ * Fetch issue templates from a repository via GitHub API
71
+ *
72
+ * @param repo - Repository client implementing IRepository
73
+ * @returns Array of parsed issue templates
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const repo = await getRepository({ type: 'github', owner: 'org', repo: 'name', token });
78
+ * const templates = await fetchIssueTemplates(repo);
79
+ * // [{ name: 'Bug Report', labels: ['bug'], body: [...] }, ...]
80
+ * ```
81
+ */
82
+ export declare function fetchIssueTemplates(repo: IRepository): Promise<IssueTemplate[]>;
83
+
84
+ /**
85
+ * Get a specific field value from an issue body
86
+ *
87
+ * @param body - The issue body markdown
88
+ * @param fieldIdOrLabel - Field ID (with template) or label (without template)
89
+ * @param template - Optional template for field ID lookup
90
+ * @returns Field value or undefined if not found
91
+ */
92
+ export declare function getIssueField(body: string, fieldIdOrLabel: string, template?: IssueTemplate): string | undefined;
93
+
94
+ /**
95
+ * Get a repository client instance
96
+ *
97
+ * This is the main entry point following the pattern from @happyvertical/files and @happyvertical/sql.
98
+ * It can accept either a configuration object or an existing repository instance.
99
+ *
100
+ * @param options - Repository configuration or existing repository instance
101
+ * @returns Promise resolving to repository interface
102
+ *
103
+ * @example
104
+ * ```typescript
105
+ * import { getRepository } from '@happyvertical/repos';
106
+ *
107
+ * // Create a GitHub repository client
108
+ * const repo = await getRepository({
109
+ * type: 'github',
110
+ * owner: 'happyvertical',
111
+ * repo: 'sdk',
112
+ * token: process.env.GITHUB_TOKEN
113
+ * });
114
+ *
115
+ * // Use the client
116
+ * const issue = await repo.getIssue(352);
117
+ * await repo.addLabels(352, ['type: feature', 'priority: high']);
118
+ *
119
+ * // Pass existing instance (returns it unchanged)
120
+ * const sameRepo = await getRepository(repo);
121
+ * ```
122
+ */
123
+ export declare function getRepository(options: RepositoryConfig | IRepository): Promise<IRepository>;
124
+
125
+ /**
126
+ * GitHub repository implementation
127
+ */
128
+ export declare class GitHubRepository implements IRepository {
129
+ private rest;
130
+ private graphql;
131
+ private owner;
132
+ private repo;
133
+ constructor(config: RepositoryConfig);
134
+ getRepository(): Promise<Repository>;
135
+ getIssue(number: number): Promise<Issue>;
136
+ createIssue(data: CreateIssueInput): Promise<Issue>;
137
+ updateIssue(number: number, data: UpdateIssueInput): Promise<Issue>;
138
+ closeIssue(number: number): Promise<void>;
139
+ addLabels(issueNumber: number, labels: string[]): Promise<void>;
140
+ removeLabel(issueNumber: number, label: string): Promise<void>;
141
+ createLabel(label: Label): Promise<void>;
142
+ updateLabel(name: string, label: Label): Promise<void>;
143
+ listLabels(): Promise<Label[]>;
144
+ addComment(issueNumber: number, body: string): Promise<Comment_2>;
145
+ updateComment(commentId: string, body: string): Promise<Comment_2>;
146
+ deleteComment(commentId: string): Promise<void>;
147
+ listComments(issueNumber: number): Promise<Comment_2[]>;
148
+ assignIssue(issueNumber: number, assignees: string[]): Promise<void>;
149
+ unassignIssue(issueNumber: number, assignees: string[]): Promise<void>;
150
+ getPullRequest(number: number): Promise<PullRequest>;
151
+ createPullRequest(data: CreatePRInput): Promise<PullRequest>;
152
+ mergePullRequest(number: number, method?: MergeMethod): Promise<void>;
153
+ searchIssues(query: string, filters?: SearchFilters): Promise<Issue[]>;
154
+ getIssueNodeId(issueNumber: number): Promise<string>;
155
+ getPRNodeId(prNumber: number): Promise<string>;
156
+ createBranch(name: string, fromRef: string): Promise<Branch>;
157
+ deleteBranch(name: string): Promise<void>;
158
+ getBranch(name: string): Promise<Branch | null>;
159
+ markPRReady(prNumber: number): Promise<void>;
160
+ convertPRToDraft(prNumber: number): Promise<void>;
161
+ requestReview(prNumber: number, reviewers: string[]): Promise<void>;
162
+ triggerWorkflow(workflowId: string, ref: string, inputs?: Record<string, string>): Promise<void>;
163
+ findPRsForIssue(issueNumber: number): Promise<PullRequest[]>;
164
+ findIssueForPR(prNumber: number): Promise<Issue | null>;
165
+ getFileContent(path: string, ref?: string): Promise<string | null>;
166
+ listDirectoryFiles(path: string, ref?: string): Promise<string[]>;
167
+ /**
168
+ * Create a new repository from this repository as a template.
169
+ *
170
+ * Uses the GitHub "Generate" API: POST /repos/{template_owner}/{template_repo}/generate
171
+ * The current repository (this.owner/this.repo) is used as the template.
172
+ */
173
+ createRepositoryFromTemplate(options: CreateFromTemplateOptions): Promise<Repository>;
174
+ }
175
+
176
+ /**
177
+ * Repository interface - all repository implementations must implement this
178
+ */
179
+ export declare interface IRepository {
180
+ getRepository(): Promise<Repository>;
181
+ getIssue(number: number): Promise<Issue>;
182
+ createIssue(data: CreateIssueInput): Promise<Issue>;
183
+ updateIssue(number: number, data: UpdateIssueInput): Promise<Issue>;
184
+ closeIssue(number: number): Promise<void>;
185
+ addLabels(issueNumber: number, labels: string[]): Promise<void>;
186
+ removeLabel(issueNumber: number, label: string): Promise<void>;
187
+ createLabel(label: Label): Promise<void>;
188
+ updateLabel(name: string, label: Label): Promise<void>;
189
+ listLabels(): Promise<Label[]>;
190
+ addComment(issueNumber: number, body: string): Promise<Comment_2>;
191
+ updateComment(commentId: string, body: string): Promise<Comment_2>;
192
+ deleteComment(commentId: string): Promise<void>;
193
+ listComments(issueNumber: number): Promise<Comment_2[]>;
194
+ assignIssue(issueNumber: number, assignees: string[]): Promise<void>;
195
+ unassignIssue(issueNumber: number, assignees: string[]): Promise<void>;
196
+ getPullRequest(number: number): Promise<PullRequest>;
197
+ createPullRequest(data: CreatePRInput): Promise<PullRequest>;
198
+ mergePullRequest(number: number, method?: MergeMethod): Promise<void>;
199
+ searchIssues(query: string, filters?: SearchFilters): Promise<Issue[]>;
200
+ getIssueNodeId(issueNumber: number): Promise<string>;
201
+ getPRNodeId(prNumber: number): Promise<string>;
202
+ createBranch(name: string, fromRef: string): Promise<Branch>;
203
+ deleteBranch(name: string): Promise<void>;
204
+ getBranch(name: string): Promise<Branch | null>;
205
+ markPRReady(prNumber: number): Promise<void>;
206
+ convertPRToDraft(prNumber: number): Promise<void>;
207
+ requestReview(prNumber: number, reviewers: string[]): Promise<void>;
208
+ triggerWorkflow(workflowId: string, ref: string, inputs?: Record<string, string>): Promise<void>;
209
+ findPRsForIssue(issueNumber: number): Promise<PullRequest[]>;
210
+ findIssueForPR(prNumber: number): Promise<Issue | null>;
211
+ getFileContent(path: string, ref?: string): Promise<string | null>;
212
+ listDirectoryFiles(path: string, ref?: string): Promise<string[]>;
213
+ }
214
+
215
+ export declare interface Issue {
216
+ number: number;
217
+ id: string;
218
+ title: string;
219
+ body: string;
220
+ state: 'open' | 'closed';
221
+ labels: Label[];
222
+ assignees: User[];
223
+ author: User;
224
+ createdAt: Date;
225
+ updatedAt: Date;
226
+ closedAt?: Date;
227
+ url: string;
228
+ commentsCount: number;
229
+ }
230
+
231
+ /**
232
+ * Issue template definition
233
+ */
234
+ export declare interface IssueTemplate {
235
+ name: string;
236
+ description?: string;
237
+ title?: string;
238
+ labels?: string[];
239
+ assignees?: string[];
240
+ body: TemplateField[];
241
+ }
242
+
243
+ export declare interface Label {
244
+ name: string;
245
+ color: string;
246
+ description: string;
247
+ }
248
+
249
+ /**
250
+ * Load and parse an issue template from a YAML file
251
+ *
252
+ * @param yamlPath - Path to the YAML template file
253
+ * @returns Parsed issue template
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * const template = await loadIssueTemplate('.github/ISSUE_TEMPLATE/bug_report.yml');
258
+ * ```
259
+ */
260
+ export declare function loadIssueTemplate(yamlPath: string): Promise<IssueTemplate>;
261
+
262
+ export declare type MergeMethod = 'merge' | 'squash' | 'rebase';
263
+
264
+ /**
265
+ * Parse an issue body into field values
266
+ *
267
+ * GitHub renders form fields as markdown sections:
268
+ * ```
269
+ * ### Label
270
+ *
271
+ * Content here
272
+ *
273
+ * ### Next Label
274
+ * ```
275
+ *
276
+ * Without a template, returns a Record<string, string> keyed by label.
277
+ * With a template, returns a Record<string, string> keyed by field ID.
278
+ *
279
+ * @param body - The issue body markdown
280
+ * @param template - Optional template for mapping labels to field IDs
281
+ * @returns Parsed fields as key-value pairs
282
+ *
283
+ * @example
284
+ * ```typescript
285
+ * // Without template - keyed by label
286
+ * const fields = parseIssueBody(issue.body);
287
+ * // { 'Description': '...', 'Steps to Reproduce': '...' }
288
+ *
289
+ * // With template - keyed by field ID
290
+ * const template = await loadIssueTemplate('.github/ISSUE_TEMPLATE/bug_report.yml');
291
+ * const fields = parseIssueBody(issue.body, template);
292
+ * // { description: '...', reproduction: '...' }
293
+ * ```
294
+ */
295
+ export declare function parseIssueBody(body: string, template?: IssueTemplate): Record<string, string>;
296
+
297
+ /**
298
+ * Parse an issue template from YAML content
299
+ *
300
+ * @param yamlContent - YAML content string
301
+ * @returns Parsed issue template
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * const template = parseIssueTemplate(`
306
+ * name: Bug Report
307
+ * body:
308
+ * - type: textarea
309
+ * id: description
310
+ * attributes:
311
+ * label: Description
312
+ * `);
313
+ * ```
314
+ */
315
+ export declare function parseIssueTemplate(yamlContent: string): IssueTemplate;
316
+
317
+ export declare interface PullRequest extends Issue {
318
+ headRef: string;
319
+ baseRef: string;
320
+ merged: boolean;
321
+ mergedAt?: Date;
322
+ mergeable: boolean;
323
+ draft: boolean;
324
+ }
325
+
326
+ /**
327
+ * Render fields into an issue body markdown string
328
+ *
329
+ * Without a template, uses field keys as labels.
330
+ * With a template, uses field IDs to look up labels and renders in template order.
331
+ *
332
+ * @param fields - Field values as key-value pairs
333
+ * @param template - Optional template for field ordering and labels
334
+ * @returns Markdown string for issue body
335
+ *
336
+ * @example
337
+ * ```typescript
338
+ * // Without template
339
+ * const body = renderIssueBody({
340
+ * 'Description': 'Bug description here',
341
+ * 'Steps to Reproduce': '1. Do X\n2. See error'
342
+ * });
343
+ *
344
+ * // With template
345
+ * const template = await loadIssueTemplate('.github/ISSUE_TEMPLATE/bug_report.yml');
346
+ * const body = renderIssueBody({
347
+ * description: 'Bug description here',
348
+ * reproduction: '1. Do X\n2. See error'
349
+ * }, template);
350
+ * ```
351
+ */
352
+ export declare function renderIssueBody(fields: Record<string, string>, template?: IssueTemplate): string;
353
+
354
+ export declare interface Repository {
355
+ owner: string;
356
+ name: string;
357
+ description: string;
358
+ defaultBranch: string;
359
+ url: string;
360
+ isPrivate: boolean;
361
+ }
362
+
363
+ /**
364
+ * Repository configuration
365
+ */
366
+ export declare interface RepositoryConfig {
367
+ type: 'github' | 'gitlab' | 'bitbucket' | 'azure';
368
+ owner: string;
369
+ repo: string;
370
+ token: string;
371
+ baseUrl?: string;
372
+ }
373
+
374
+ export declare class RepositoryError extends Error {
375
+ code: RepositoryErrorCode;
376
+ statusCode?: number | undefined;
377
+ response?: unknown | undefined;
378
+ constructor(message: string, code: RepositoryErrorCode, statusCode?: number | undefined, response?: unknown | undefined);
379
+ static fromHTTPStatus(statusCode: number, message: string, response?: unknown): RepositoryError;
380
+ static networkError(message: string, cause?: Error): RepositoryError;
381
+ isRetryable(): boolean;
382
+ }
383
+
384
+ /**
385
+ * Repository error handling
386
+ */
387
+ export declare enum RepositoryErrorCode {
388
+ NOT_FOUND = "NOT_FOUND",
389
+ UNAUTHORIZED = "UNAUTHORIZED",
390
+ FORBIDDEN = "FORBIDDEN",
391
+ RATE_LIMITED = "RATE_LIMITED",
392
+ VALIDATION_ERROR = "VALIDATION_ERROR",
393
+ NETWORK_ERROR = "NETWORK_ERROR",
394
+ UNKNOWN = "UNKNOWN"
395
+ }
396
+
397
+ export declare interface SearchFilters {
398
+ state?: 'open' | 'closed' | 'all';
399
+ labels?: string[];
400
+ author?: string;
401
+ assignee?: string;
402
+ limit?: number;
403
+ sort?: 'created' | 'updated' | 'comments';
404
+ order?: 'asc' | 'desc';
405
+ }
406
+
407
+ /**
408
+ * Template field definition - mirrors GitHub ISSUE_TEMPLATE YAML structure
409
+ */
410
+ export declare interface TemplateField {
411
+ type: 'textarea' | 'input' | 'dropdown' | 'checkboxes' | 'markdown';
412
+ id?: string;
413
+ attributes: {
414
+ label: string;
415
+ description?: string;
416
+ placeholder?: string;
417
+ value?: string;
418
+ options?: string[];
419
+ };
420
+ validations?: {
421
+ required?: boolean;
422
+ };
423
+ }
424
+
425
+ /**
426
+ * Update a specific field in an issue body
427
+ *
428
+ * @param body - The issue body markdown
429
+ * @param fieldIdOrLabel - Field ID (with template) or label (without template)
430
+ * @param value - New value for the field
431
+ * @param template - Optional template for field ID lookup
432
+ * @returns Updated issue body markdown
433
+ */
434
+ export declare function updateIssueField(body: string, fieldIdOrLabel: string, value: string, template?: IssueTemplate): string;
435
+
436
+ export declare interface UpdateIssueInput {
437
+ title?: string;
438
+ body?: string;
439
+ state?: 'open' | 'closed';
440
+ }
441
+
442
+ /**
443
+ * Core types for repository operations
444
+ */
445
+ export declare interface User {
446
+ login: string;
447
+ id: string;
448
+ type: 'User' | 'Bot';
449
+ avatarUrl?: string;
450
+ url?: string;
451
+ }
452
+
453
+ export { }