millhouse 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +8 -0
- package/README.md +248 -0
- package/commands/millhouse.md +223 -0
- package/dist/analysis/graph-builder.d.ts +42 -0
- package/dist/analysis/graph-builder.d.ts.map +1 -0
- package/dist/analysis/graph-builder.js +98 -0
- package/dist/analysis/graph-builder.js.map +1 -0
- package/dist/analysis/issue-analyzer.d.ts +20 -0
- package/dist/analysis/issue-analyzer.d.ts.map +1 -0
- package/dist/analysis/issue-analyzer.js +167 -0
- package/dist/analysis/issue-analyzer.js.map +1 -0
- package/dist/analysis/plan-parser.d.ts +8 -0
- package/dist/analysis/plan-parser.d.ts.map +1 -0
- package/dist/analysis/plan-parser.js +112 -0
- package/dist/analysis/plan-parser.js.map +1 -0
- package/dist/cli/cleanup.d.ts +20 -0
- package/dist/cli/cleanup.d.ts.map +1 -0
- package/dist/cli/cleanup.js +186 -0
- package/dist/cli/cleanup.js.map +1 -0
- package/dist/cli/commands/clean.d.ts +2 -0
- package/dist/cli/commands/clean.d.ts.map +1 -0
- package/dist/cli/commands/clean.js +16 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/resume.d.ts +2 -0
- package/dist/cli/commands/resume.d.ts.map +1 -0
- package/dist/cli/commands/resume.js +82 -0
- package/dist/cli/commands/resume.js.map +1 -0
- package/dist/cli/commands/run.d.ts +10 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +352 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +6 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +74 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/status.d.ts +7 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +83 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/progress-display.d.ts +93 -0
- package/dist/cli/progress-display.d.ts.map +1 -0
- package/dist/cli/progress-display.js +318 -0
- package/dist/cli/progress-display.js.map +1 -0
- package/dist/core/orchestrator.d.ts +79 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js +389 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/scheduler.d.ts +72 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +234 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/execution/claude-runner.d.ts +41 -0
- package/dist/execution/claude-runner.d.ts.map +1 -0
- package/dist/execution/claude-runner.js +241 -0
- package/dist/execution/claude-runner.js.map +1 -0
- package/dist/execution/worktree-manager.d.ts +52 -0
- package/dist/execution/worktree-manager.d.ts.map +1 -0
- package/dist/execution/worktree-manager.js +208 -0
- package/dist/execution/worktree-manager.js.map +1 -0
- package/dist/github/client.d.ts +27 -0
- package/dist/github/client.d.ts.map +1 -0
- package/dist/github/client.js +178 -0
- package/dist/github/client.js.map +1 -0
- package/dist/github/issue-discoverer.d.ts +20 -0
- package/dist/github/issue-discoverer.d.ts.map +1 -0
- package/dist/github/issue-discoverer.js +83 -0
- package/dist/github/issue-discoverer.js.map +1 -0
- package/dist/github/label-manager.d.ts +44 -0
- package/dist/github/label-manager.d.ts.map +1 -0
- package/dist/github/label-manager.js +93 -0
- package/dist/github/label-manager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/dist/storage/config.d.ts +4 -0
- package/dist/storage/config.d.ts.map +1 -0
- package/dist/storage/config.js +25 -0
- package/dist/storage/config.js.map +1 -0
- package/dist/storage/json-store.d.ts +20 -0
- package/dist/storage/json-store.d.ts.map +1 -0
- package/dist/storage/json-store.js +92 -0
- package/dist/storage/json-store.js.map +1 -0
- package/dist/types.d.ts +142 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +36 -0
- package/dist/types.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { execSync, exec } from 'node:child_process';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { promisify } from 'node:util';
|
|
5
|
+
const execAsync = promisify(exec);
|
|
6
|
+
export class WorktreeManager {
|
|
7
|
+
basePath;
|
|
8
|
+
worktreesDir;
|
|
9
|
+
constructor(basePath = process.cwd()) {
|
|
10
|
+
this.basePath = basePath;
|
|
11
|
+
this.worktreesDir = path.join(basePath, '.millhouse', 'worktrees');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create the run branch from the base branch.
|
|
15
|
+
*/
|
|
16
|
+
async createRunBranch(runId, baseBranch) {
|
|
17
|
+
const runBranch = `millhouse/run-${runId}`;
|
|
18
|
+
// Fetch latest from remote
|
|
19
|
+
try {
|
|
20
|
+
await execAsync('git fetch origin', { cwd: this.basePath });
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Might not have remote, continue anyway
|
|
24
|
+
}
|
|
25
|
+
// Create the run branch from base
|
|
26
|
+
try {
|
|
27
|
+
await execAsync(`git checkout -b ${runBranch} origin/${baseBranch}`, { cwd: this.basePath });
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Try without origin/ prefix
|
|
31
|
+
await execAsync(`git checkout -b ${runBranch} ${baseBranch}`, { cwd: this.basePath });
|
|
32
|
+
}
|
|
33
|
+
// Go back to original branch
|
|
34
|
+
await execAsync(`git checkout -`, { cwd: this.basePath });
|
|
35
|
+
return runBranch;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create an isolated worktree for an issue.
|
|
39
|
+
* Each issue gets its own branch to allow parallel worktrees.
|
|
40
|
+
*/
|
|
41
|
+
async createWorktree(runId, issueNumber, runBranch) {
|
|
42
|
+
await fs.mkdir(this.worktreesDir, { recursive: true });
|
|
43
|
+
const worktreePath = path.join(this.worktreesDir, `run-${runId}-issue-${issueNumber}`);
|
|
44
|
+
// Each issue gets its own branch forked from the run branch
|
|
45
|
+
// Use -issue- instead of /issue- to avoid git ref conflicts
|
|
46
|
+
const issueBranch = `${runBranch}-issue-${issueNumber}`;
|
|
47
|
+
// Remove existing worktree if any
|
|
48
|
+
await this.removeWorktree(worktreePath).catch(() => { });
|
|
49
|
+
// Delete the issue branch if it exists (from a previous failed run)
|
|
50
|
+
await execAsync(`git branch -D ${issueBranch}`, { cwd: this.basePath }).catch(() => { });
|
|
51
|
+
// Create worktree with a new branch forked from run branch
|
|
52
|
+
await execAsync(`git worktree add -b ${issueBranch} "${worktreePath}" ${runBranch}`, { cwd: this.basePath });
|
|
53
|
+
const worktreeInfo = {
|
|
54
|
+
issueNumber,
|
|
55
|
+
runId,
|
|
56
|
+
path: worktreePath,
|
|
57
|
+
branch: issueBranch,
|
|
58
|
+
createdAt: new Date().toISOString(),
|
|
59
|
+
};
|
|
60
|
+
return worktreeInfo;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get list of commits made in a worktree since it was created.
|
|
64
|
+
*/
|
|
65
|
+
async getNewCommits(worktreePath, runBranch) {
|
|
66
|
+
try {
|
|
67
|
+
// Get commits that are in worktree HEAD but not in run branch
|
|
68
|
+
const { stdout } = await execAsync(`git log ${runBranch}..HEAD --format=%H`, { cwd: worktreePath });
|
|
69
|
+
return stdout.trim().split('\n').filter(Boolean);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Merge changes from a worktree back into the run branch.
|
|
77
|
+
* Returns true if successful, false if there were conflicts.
|
|
78
|
+
*/
|
|
79
|
+
async mergeWorktree(worktreePath, runBranch) {
|
|
80
|
+
try {
|
|
81
|
+
// Get the current HEAD of the worktree
|
|
82
|
+
const { stdout: worktreeHead } = await execAsync('git rev-parse HEAD', { cwd: worktreePath });
|
|
83
|
+
const commitHash = worktreeHead.trim();
|
|
84
|
+
// Check if there are any new commits
|
|
85
|
+
const commits = await this.getNewCommits(worktreePath, runBranch);
|
|
86
|
+
if (commits.length === 0) {
|
|
87
|
+
return { success: true };
|
|
88
|
+
}
|
|
89
|
+
// Switch to run branch in main repo and merge
|
|
90
|
+
const originalBranch = execSync('git branch --show-current', {
|
|
91
|
+
cwd: this.basePath,
|
|
92
|
+
encoding: 'utf-8',
|
|
93
|
+
}).trim();
|
|
94
|
+
try {
|
|
95
|
+
await execAsync(`git checkout ${runBranch}`, { cwd: this.basePath });
|
|
96
|
+
await execAsync(`git merge ${commitHash} --no-edit`, { cwd: this.basePath });
|
|
97
|
+
return { success: true };
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
// Return to original branch if different
|
|
101
|
+
if (originalBranch && originalBranch !== runBranch) {
|
|
102
|
+
await execAsync(`git checkout ${originalBranch}`, { cwd: this.basePath }).catch(() => { });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
108
|
+
// Check if it's a merge conflict
|
|
109
|
+
if (errorMessage.includes('CONFLICT') || errorMessage.includes('Merge conflict')) {
|
|
110
|
+
// Abort the merge
|
|
111
|
+
await execAsync('git merge --abort', { cwd: this.basePath }).catch(() => { });
|
|
112
|
+
return { success: false, error: 'Merge conflict detected' };
|
|
113
|
+
}
|
|
114
|
+
return { success: false, error: errorMessage };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Remove a worktree and its associated branch.
|
|
119
|
+
*/
|
|
120
|
+
async removeWorktree(worktreePath, issueBranch) {
|
|
121
|
+
try {
|
|
122
|
+
await execAsync(`git worktree remove "${worktreePath}" --force`, { cwd: this.basePath });
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Try to remove directory manually if git worktree fails
|
|
126
|
+
await fs.rm(worktreePath, { recursive: true, force: true });
|
|
127
|
+
await execAsync('git worktree prune', { cwd: this.basePath }).catch(() => { });
|
|
128
|
+
}
|
|
129
|
+
// Clean up the issue branch if provided
|
|
130
|
+
if (issueBranch) {
|
|
131
|
+
await execAsync(`git branch -D ${issueBranch}`, { cwd: this.basePath }).catch(() => { });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Clean up all worktrees for a run.
|
|
136
|
+
*/
|
|
137
|
+
async cleanupRun(_runId) {
|
|
138
|
+
try {
|
|
139
|
+
const entries = await fs.readdir(this.worktreesDir);
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
const worktreePath = path.join(this.worktreesDir, entry);
|
|
142
|
+
await this.removeWorktree(worktreePath);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Directory might not exist
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Push the run branch to remote.
|
|
151
|
+
*/
|
|
152
|
+
async pushRunBranch(runBranch) {
|
|
153
|
+
await execAsync(`git push -u origin ${runBranch}`, { cwd: this.basePath });
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if there are uncommitted changes in the main repo.
|
|
157
|
+
*/
|
|
158
|
+
async hasUncommittedChanges() {
|
|
159
|
+
try {
|
|
160
|
+
const { stdout } = await execAsync('git status --porcelain', { cwd: this.basePath });
|
|
161
|
+
return stdout.trim().length > 0;
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get the current branch name.
|
|
169
|
+
*/
|
|
170
|
+
async getCurrentBranch() {
|
|
171
|
+
const { stdout } = await execAsync('git branch --show-current', { cwd: this.basePath });
|
|
172
|
+
return stdout.trim();
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Restore to a specific branch, aborting any in-progress merge.
|
|
176
|
+
*/
|
|
177
|
+
async restoreBranch(branchName) {
|
|
178
|
+
// Abort any in-progress merge
|
|
179
|
+
try {
|
|
180
|
+
await execAsync('git merge --abort', { cwd: this.basePath });
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// No merge in progress, that's fine
|
|
184
|
+
}
|
|
185
|
+
// Abort any in-progress rebase
|
|
186
|
+
try {
|
|
187
|
+
await execAsync('git rebase --abort', { cwd: this.basePath });
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// No rebase in progress, that's fine
|
|
191
|
+
}
|
|
192
|
+
// Discard any uncommitted changes
|
|
193
|
+
try {
|
|
194
|
+
await execAsync('git checkout -- .', { cwd: this.basePath });
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Might fail if no changes, that's fine
|
|
198
|
+
}
|
|
199
|
+
// Switch back to original branch
|
|
200
|
+
try {
|
|
201
|
+
await execAsync(`git checkout "${branchName}"`, { cwd: this.basePath });
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// Branch might not exist or other issue
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=worktree-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-manager.js","sourceRoot":"","sources":["../../src/execution/worktree-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { GitHubIssue } from '../types.js';
|
|
2
|
+
export declare class GitHubClient {
|
|
3
|
+
private octokit;
|
|
4
|
+
private owner;
|
|
5
|
+
private repo;
|
|
6
|
+
constructor();
|
|
7
|
+
private getGitHubToken;
|
|
8
|
+
private getRepoInfo;
|
|
9
|
+
get repoOwner(): string;
|
|
10
|
+
get repoName(): string;
|
|
11
|
+
getIssue(issueNumber: number): Promise<GitHubIssue>;
|
|
12
|
+
getIssues(issueNumbers: number[]): Promise<GitHubIssue[]>;
|
|
13
|
+
listOpenIssues(): Promise<GitHubIssue[]>;
|
|
14
|
+
addLabels(issueNumber: number, labels: string[]): Promise<void>;
|
|
15
|
+
removeLabel(issueNumber: number, label: string): Promise<void>;
|
|
16
|
+
setLabels(issueNumber: number, labels: string[]): Promise<void>;
|
|
17
|
+
createLabel(name: string, color: string, description?: string): Promise<void>;
|
|
18
|
+
addComment(issueNumber: number, body: string): Promise<void>;
|
|
19
|
+
createPullRequest(options: {
|
|
20
|
+
title: string;
|
|
21
|
+
body: string;
|
|
22
|
+
head: string;
|
|
23
|
+
base: string;
|
|
24
|
+
draft?: boolean;
|
|
25
|
+
}): Promise<string>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/github/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,IAAI,CAAS;;IAsBrB,OAAO,CAAC,cAAc;IAetB,OAAO,CAAC,WAAW;IAqBnB,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAEK,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAkBnD,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAKzD,cAAc,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAoCxC,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/D,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa9D,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/D,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc7E,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5D,iBAAiB,CAAC,OAAO,EAAE;QAC/B,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,GAAG,OAAO,CAAC,MAAM,CAAC;CAapB"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { Octokit } from '@octokit/rest';
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
export class GitHubClient {
|
|
4
|
+
octokit;
|
|
5
|
+
owner;
|
|
6
|
+
repo;
|
|
7
|
+
constructor() {
|
|
8
|
+
// Get token from gh CLI or environment
|
|
9
|
+
const token = this.getGitHubToken();
|
|
10
|
+
this.octokit = new Octokit({
|
|
11
|
+
auth: token,
|
|
12
|
+
log: {
|
|
13
|
+
// Silence Octokit's built-in logging
|
|
14
|
+
debug: () => { },
|
|
15
|
+
info: () => { },
|
|
16
|
+
warn: () => { },
|
|
17
|
+
error: () => { },
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
// Get repo info from git remote
|
|
21
|
+
const { owner, repo } = this.getRepoInfo();
|
|
22
|
+
this.owner = owner;
|
|
23
|
+
this.repo = repo;
|
|
24
|
+
}
|
|
25
|
+
getGitHubToken() {
|
|
26
|
+
// First try environment variable
|
|
27
|
+
if (process.env.GITHUB_TOKEN) {
|
|
28
|
+
return process.env.GITHUB_TOKEN;
|
|
29
|
+
}
|
|
30
|
+
// Try gh CLI
|
|
31
|
+
try {
|
|
32
|
+
const token = execSync('gh auth token', { encoding: 'utf-8' }).trim();
|
|
33
|
+
return token;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new Error('No GitHub token found. Run "gh auth login" or set GITHUB_TOKEN');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
getRepoInfo() {
|
|
40
|
+
try {
|
|
41
|
+
const remoteUrl = execSync('git remote get-url origin', { encoding: 'utf-8' }).trim();
|
|
42
|
+
// Parse GitHub URL (SSH or HTTPS)
|
|
43
|
+
const sshMatch = remoteUrl.match(/git@github\.com:([^/]+)\/(.+?)(?:\.git)?$/);
|
|
44
|
+
if (sshMatch) {
|
|
45
|
+
return { owner: sshMatch[1], repo: sshMatch[2] };
|
|
46
|
+
}
|
|
47
|
+
const httpsMatch = remoteUrl.match(/github\.com\/([^/]+)\/(.+?)(?:\.git)?$/);
|
|
48
|
+
if (httpsMatch) {
|
|
49
|
+
return { owner: httpsMatch[1], repo: httpsMatch[2] };
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`Cannot parse GitHub URL: ${remoteUrl}`);
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
throw new Error(`Failed to get repo info: ${error instanceof Error ? error.message : error}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
get repoOwner() {
|
|
58
|
+
return this.owner;
|
|
59
|
+
}
|
|
60
|
+
get repoName() {
|
|
61
|
+
return this.repo;
|
|
62
|
+
}
|
|
63
|
+
async getIssue(issueNumber) {
|
|
64
|
+
const response = await this.octokit.issues.get({
|
|
65
|
+
owner: this.owner,
|
|
66
|
+
repo: this.repo,
|
|
67
|
+
issue_number: issueNumber,
|
|
68
|
+
});
|
|
69
|
+
return {
|
|
70
|
+
number: response.data.number,
|
|
71
|
+
title: response.data.title,
|
|
72
|
+
body: response.data.body ?? null,
|
|
73
|
+
state: response.data.state,
|
|
74
|
+
labels: response.data.labels.map(l => (typeof l === 'string' ? l : l.name || '')),
|
|
75
|
+
url: response.data.url,
|
|
76
|
+
htmlUrl: response.data.html_url,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async getIssues(issueNumbers) {
|
|
80
|
+
const promises = issueNumbers.map(n => this.getIssue(n));
|
|
81
|
+
return Promise.all(promises);
|
|
82
|
+
}
|
|
83
|
+
async listOpenIssues() {
|
|
84
|
+
const issues = [];
|
|
85
|
+
let page = 1;
|
|
86
|
+
while (true) {
|
|
87
|
+
const response = await this.octokit.issues.listForRepo({
|
|
88
|
+
owner: this.owner,
|
|
89
|
+
repo: this.repo,
|
|
90
|
+
state: 'open',
|
|
91
|
+
per_page: 100,
|
|
92
|
+
page,
|
|
93
|
+
});
|
|
94
|
+
if (response.data.length === 0)
|
|
95
|
+
break;
|
|
96
|
+
for (const issue of response.data) {
|
|
97
|
+
// Skip pull requests (GitHub API returns them as issues)
|
|
98
|
+
if (issue.pull_request)
|
|
99
|
+
continue;
|
|
100
|
+
issues.push({
|
|
101
|
+
number: issue.number,
|
|
102
|
+
title: issue.title,
|
|
103
|
+
body: issue.body ?? null,
|
|
104
|
+
state: issue.state,
|
|
105
|
+
labels: issue.labels.map(l => (typeof l === 'string' ? l : l.name || '')),
|
|
106
|
+
url: issue.url,
|
|
107
|
+
htmlUrl: issue.html_url,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
page++;
|
|
111
|
+
}
|
|
112
|
+
return issues;
|
|
113
|
+
}
|
|
114
|
+
async addLabels(issueNumber, labels) {
|
|
115
|
+
await this.octokit.issues.addLabels({
|
|
116
|
+
owner: this.owner,
|
|
117
|
+
repo: this.repo,
|
|
118
|
+
issue_number: issueNumber,
|
|
119
|
+
labels,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async removeLabel(issueNumber, label) {
|
|
123
|
+
try {
|
|
124
|
+
await this.octokit.issues.removeLabel({
|
|
125
|
+
owner: this.owner,
|
|
126
|
+
repo: this.repo,
|
|
127
|
+
issue_number: issueNumber,
|
|
128
|
+
name: label,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Label might not exist, ignore
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async setLabels(issueNumber, labels) {
|
|
136
|
+
await this.octokit.issues.setLabels({
|
|
137
|
+
owner: this.owner,
|
|
138
|
+
repo: this.repo,
|
|
139
|
+
issue_number: issueNumber,
|
|
140
|
+
labels,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
async createLabel(name, color, description) {
|
|
144
|
+
try {
|
|
145
|
+
await this.octokit.issues.createLabel({
|
|
146
|
+
owner: this.owner,
|
|
147
|
+
repo: this.repo,
|
|
148
|
+
name,
|
|
149
|
+
color,
|
|
150
|
+
description,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// Label might already exist
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async addComment(issueNumber, body) {
|
|
158
|
+
await this.octokit.issues.createComment({
|
|
159
|
+
owner: this.owner,
|
|
160
|
+
repo: this.repo,
|
|
161
|
+
issue_number: issueNumber,
|
|
162
|
+
body,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
async createPullRequest(options) {
|
|
166
|
+
const response = await this.octokit.pulls.create({
|
|
167
|
+
owner: this.owner,
|
|
168
|
+
repo: this.repo,
|
|
169
|
+
title: options.title,
|
|
170
|
+
body: options.body,
|
|
171
|
+
head: options.head,
|
|
172
|
+
base: options.base,
|
|
173
|
+
draft: options.draft ?? true,
|
|
174
|
+
});
|
|
175
|
+
return response.data.html_url;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/github/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { GitHubClient } from './client.js';
|
|
2
|
+
import type { GitHubIssue } from '../types.js';
|
|
3
|
+
export declare class IssueDiscoverer {
|
|
4
|
+
private client;
|
|
5
|
+
constructor(client: GitHubClient);
|
|
6
|
+
/**
|
|
7
|
+
* Discovers all issues starting from the given issue numbers.
|
|
8
|
+
* If recursive is true, follows linked issues in descriptions.
|
|
9
|
+
*/
|
|
10
|
+
discover(issueNumbers: number[], recursive: boolean): Promise<GitHubIssue[]>;
|
|
11
|
+
/**
|
|
12
|
+
* Parse issue body for linked issue references.
|
|
13
|
+
* Handles:
|
|
14
|
+
* - Direct references: #123
|
|
15
|
+
* - Task lists: - [ ] #123
|
|
16
|
+
* - URLs: github.com/owner/repo/issues/123
|
|
17
|
+
*/
|
|
18
|
+
private parseLinkedIssues;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=issue-discoverer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-discoverer.d.ts","sourceRoot":"","sources":["../../src/github/issue-discoverer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,qBAAa,eAAe;IACd,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,YAAY;IAExC;;;OAGG;IACG,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA4ClF;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;CAkC1B"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
export class IssueDiscoverer {
|
|
3
|
+
client;
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Discovers all issues starting from the given issue numbers.
|
|
9
|
+
* If recursive is true, follows linked issues in descriptions.
|
|
10
|
+
*/
|
|
11
|
+
async discover(issueNumbers, recursive) {
|
|
12
|
+
const discovered = new Map();
|
|
13
|
+
const toProcess = new Set(issueNumbers);
|
|
14
|
+
const processed = new Set();
|
|
15
|
+
console.log(chalk.gray(` Starting with issues: ${issueNumbers.map(n => `#${n}`).join(', ')}`));
|
|
16
|
+
if (recursive) {
|
|
17
|
+
console.log(chalk.gray(` Recursive mode: will follow linked issues`));
|
|
18
|
+
}
|
|
19
|
+
while (toProcess.size > 0) {
|
|
20
|
+
const batch = Array.from(toProcess);
|
|
21
|
+
toProcess.clear();
|
|
22
|
+
console.log(chalk.gray(` Fetching: ${batch.map(n => `#${n}`).join(', ')}`));
|
|
23
|
+
// Fetch issues in parallel
|
|
24
|
+
const issues = await this.client.getIssues(batch);
|
|
25
|
+
for (const issue of issues) {
|
|
26
|
+
if (discovered.has(issue.number))
|
|
27
|
+
continue;
|
|
28
|
+
discovered.set(issue.number, issue);
|
|
29
|
+
processed.add(issue.number);
|
|
30
|
+
console.log(chalk.gray(` Found #${issue.number}: ${issue.title}`));
|
|
31
|
+
// If recursive, find linked issues
|
|
32
|
+
if (recursive && issue.body) {
|
|
33
|
+
const linkedIssues = this.parseLinkedIssues(issue.body);
|
|
34
|
+
const newLinked = linkedIssues.filter(n => !processed.has(n) && !discovered.has(n));
|
|
35
|
+
if (newLinked.length > 0) {
|
|
36
|
+
console.log(chalk.gray(` └─ Links to: ${newLinked.map(n => `#${n}`).join(', ')}`));
|
|
37
|
+
}
|
|
38
|
+
for (const linkedNumber of newLinked) {
|
|
39
|
+
toProcess.add(linkedNumber);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return Array.from(discovered.values());
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Parse issue body for linked issue references.
|
|
48
|
+
* Handles:
|
|
49
|
+
* - Direct references: #123
|
|
50
|
+
* - Task lists: - [ ] #123
|
|
51
|
+
* - URLs: github.com/owner/repo/issues/123
|
|
52
|
+
*/
|
|
53
|
+
parseLinkedIssues(body) {
|
|
54
|
+
const issueNumbers = new Set();
|
|
55
|
+
// Match #123 patterns (not in URLs)
|
|
56
|
+
const hashPattern = /(?:^|[^/])#(\d+)/g;
|
|
57
|
+
let match;
|
|
58
|
+
while ((match = hashPattern.exec(body)) !== null) {
|
|
59
|
+
const num = parseInt(match[1], 10);
|
|
60
|
+
if (num > 0 && num < 1000000) {
|
|
61
|
+
issueNumbers.add(num);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Match task list items: - [ ] #123 or - [x] #123
|
|
65
|
+
const taskListPattern = /- \[[ x]\] #(\d+)/gi;
|
|
66
|
+
while ((match = taskListPattern.exec(body)) !== null) {
|
|
67
|
+
const num = parseInt(match[1], 10);
|
|
68
|
+
if (num > 0 && num < 1000000) {
|
|
69
|
+
issueNumbers.add(num);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Match GitHub issue URLs for the same repo
|
|
73
|
+
const urlPattern = /github\.com\/[^/]+\/[^/]+\/issues\/(\d+)/g;
|
|
74
|
+
while ((match = urlPattern.exec(body)) !== null) {
|
|
75
|
+
const num = parseInt(match[1], 10);
|
|
76
|
+
if (num > 0 && num < 1000000) {
|
|
77
|
+
issueNumbers.add(num);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return Array.from(issueNumbers);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=issue-discoverer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-discoverer.js","sourceRoot":"","sources":["../../src/github/issue-discoverer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { GitHubClient } from './client.js';
|
|
2
|
+
import { type TaskStatus } from '../types.js';
|
|
3
|
+
export declare class LabelManager {
|
|
4
|
+
private client;
|
|
5
|
+
constructor(client: GitHubClient);
|
|
6
|
+
/**
|
|
7
|
+
* Ensure all Millhouse labels exist in the repository.
|
|
8
|
+
*/
|
|
9
|
+
ensureLabelsExist(): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Remove all Millhouse labels from an issue.
|
|
12
|
+
*/
|
|
13
|
+
clearMillhouseLabels(issueNumber: number): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Set the Millhouse status label for an issue.
|
|
16
|
+
* Removes any existing Millhouse labels first.
|
|
17
|
+
*/
|
|
18
|
+
setStatus(issueNumber: number, status: TaskStatus): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Set multiple issues to a status.
|
|
21
|
+
*/
|
|
22
|
+
setStatusBatch(issueNumbers: number[], status: TaskStatus): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Mark an issue as queued.
|
|
25
|
+
*/
|
|
26
|
+
markQueued(issueNumber: number): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Mark an issue as in progress.
|
|
29
|
+
*/
|
|
30
|
+
markInProgress(issueNumber: number): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Mark an issue as blocked.
|
|
33
|
+
*/
|
|
34
|
+
markBlocked(issueNumber: number): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Mark an issue as failed.
|
|
37
|
+
*/
|
|
38
|
+
markFailed(issueNumber: number): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Mark an issue as done.
|
|
41
|
+
*/
|
|
42
|
+
markDone(issueNumber: number): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=label-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"label-manager.d.ts","sourceRoot":"","sources":["../../src/github/label-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAyC,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AA2BrF,qBAAa,YAAY;IACX,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,YAAY;IAExC;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC;IAYxC;;OAEG;IACG,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ9D;;;OAGG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAYvE;;OAEG;IACG,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/E;;OAEG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD;;OAEG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD;;OAEG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD;;OAEG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD;;OAEG;IACG,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGnD"}
|