@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 +33 -0
- package/LICENSE +7 -0
- package/README.md +111 -0
- package/dist/claude-context.d.ts +1 -0
- package/dist/cli/claude-context.d.ts +3 -0
- package/dist/cli/claude-context.js +21 -0
- package/dist/cli/claude-context.js.map +1 -0
- package/dist/index.d.ts +453 -0
- package/dist/index.js +714 -0
- package/dist/index.js.map +1 -0
- package/metadata.json +33 -0
- package/package.json +58 -0
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,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;"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 { }
|