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,167 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { query } from '@anthropic-ai/claude-code';
|
|
3
|
+
const BATCH_ANALYSIS_PROMPT = `Analyze these GitHub issues and determine their dependencies and execution order.
|
|
4
|
+
|
|
5
|
+
## Issues to Analyze
|
|
6
|
+
|
|
7
|
+
{{issuesList}}
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Your Task
|
|
12
|
+
|
|
13
|
+
Analyze each issue and determine:
|
|
14
|
+
1. **dependencies**: Which issues MUST be completed BEFORE this issue can start
|
|
15
|
+
2. **affectedPaths**: File paths this issue will likely create or modify
|
|
16
|
+
|
|
17
|
+
Respond with ONLY a JSON array (no markdown, no explanation):
|
|
18
|
+
[
|
|
19
|
+
{
|
|
20
|
+
"issueNumber": 1,
|
|
21
|
+
"dependencies": [],
|
|
22
|
+
"affectedPaths": ["src/path/to/file.ts"]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"issueNumber": 2,
|
|
26
|
+
"dependencies": [1],
|
|
27
|
+
"affectedPaths": ["src/other/file.ts"]
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
Rules:
|
|
32
|
+
- Look for explicit dependency mentions: "depends on #X", "after #X", "blocked by #X", "requires #X"
|
|
33
|
+
- Also infer logical dependencies (e.g., if issue B imports from a file that issue A creates)
|
|
34
|
+
- Only include dependencies between issues in this list
|
|
35
|
+
- affectedPaths should be specific file paths mentioned or implied
|
|
36
|
+
- Respond with ONLY valid JSON, nothing else`;
|
|
37
|
+
export class IssueAnalyzer {
|
|
38
|
+
/**
|
|
39
|
+
* Analyze all issues in a single Claude call to determine dependencies.
|
|
40
|
+
*/
|
|
41
|
+
async analyzeIssues(issues) {
|
|
42
|
+
if (issues.length === 0)
|
|
43
|
+
return [];
|
|
44
|
+
const allIssueNumbers = issues.map(i => i.number);
|
|
45
|
+
// Build the issues list for the prompt
|
|
46
|
+
const issuesList = issues.map(issue => `### Issue #${issue.number}: ${issue.title}\n${issue.body || '(No description)'}`).join('\n\n');
|
|
47
|
+
const prompt = BATCH_ANALYSIS_PROMPT.replace('{{issuesList}}', issuesList);
|
|
48
|
+
console.log(chalk.gray(` Sending ${issues.length} issues to Claude for analysis...`));
|
|
49
|
+
try {
|
|
50
|
+
const iterator = query({
|
|
51
|
+
prompt,
|
|
52
|
+
options: {
|
|
53
|
+
maxTurns: 1,
|
|
54
|
+
allowedTools: [],
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
let responseText = '';
|
|
58
|
+
for await (const message of iterator) {
|
|
59
|
+
const msg = message;
|
|
60
|
+
if (msg.type === 'assistant') {
|
|
61
|
+
const assistantMsg = msg.message;
|
|
62
|
+
if (assistantMsg?.content && Array.isArray(assistantMsg.content)) {
|
|
63
|
+
for (const block of assistantMsg.content) {
|
|
64
|
+
if (typeof block === 'object' && block && 'type' in block && block.type === 'text' && 'text' in block) {
|
|
65
|
+
responseText += String(block.text);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Parse JSON array from response
|
|
72
|
+
const jsonMatch = responseText.match(/\[[\s\S]*\]/);
|
|
73
|
+
if (!jsonMatch) {
|
|
74
|
+
throw new Error('No JSON array found in response');
|
|
75
|
+
}
|
|
76
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
77
|
+
// Create a map for quick lookup
|
|
78
|
+
const analysisMap = new Map(parsed.map(p => [p.issueNumber, p]));
|
|
79
|
+
// Build analyzed issues
|
|
80
|
+
const results = issues.map(issue => {
|
|
81
|
+
const analysis = analysisMap.get(issue.number);
|
|
82
|
+
// Filter dependencies to only include valid issues
|
|
83
|
+
const validDeps = (analysis?.dependencies || []).filter(d => allIssueNumbers.includes(d) && d !== issue.number);
|
|
84
|
+
const analyzed = {
|
|
85
|
+
...issue,
|
|
86
|
+
affectedPaths: analysis?.affectedPaths || [],
|
|
87
|
+
dependencies: validDeps,
|
|
88
|
+
analyzedAt: new Date().toISOString(),
|
|
89
|
+
};
|
|
90
|
+
// Log each issue's analysis
|
|
91
|
+
const depsStr = validDeps.length > 0
|
|
92
|
+
? `depends on ${validDeps.map(d => `#${d}`).join(', ')}`
|
|
93
|
+
: 'no dependencies';
|
|
94
|
+
console.log(chalk.gray(` #${issue.number}: ${depsStr}`));
|
|
95
|
+
return analyzed;
|
|
96
|
+
});
|
|
97
|
+
return results;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.log(chalk.yellow(` Claude analysis failed, falling back to pattern matching: ${error}`));
|
|
101
|
+
return this.fallbackAnalysis(issues, allIssueNumbers);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Fallback to pattern matching if Claude analysis fails.
|
|
106
|
+
*/
|
|
107
|
+
fallbackAnalysis(issues, allIssueNumbers) {
|
|
108
|
+
return issues.map(issue => {
|
|
109
|
+
const deps = this.extractDependencies(issue, allIssueNumbers);
|
|
110
|
+
const paths = this.extractAffectedPaths(issue);
|
|
111
|
+
const depsStr = deps.length > 0
|
|
112
|
+
? `depends on ${deps.map(d => `#${d}`).join(', ')}`
|
|
113
|
+
: 'no dependencies';
|
|
114
|
+
console.log(chalk.gray(` #${issue.number}: ${depsStr} (pattern match)`));
|
|
115
|
+
return {
|
|
116
|
+
...issue,
|
|
117
|
+
affectedPaths: paths,
|
|
118
|
+
dependencies: deps,
|
|
119
|
+
analyzedAt: new Date().toISOString(),
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Extract dependencies using pattern matching.
|
|
125
|
+
*/
|
|
126
|
+
extractDependencies(issue, validNumbers) {
|
|
127
|
+
if (!issue.body)
|
|
128
|
+
return [];
|
|
129
|
+
const dependencies = new Set();
|
|
130
|
+
const body = issue.body;
|
|
131
|
+
const dependencyStatements = [
|
|
132
|
+
/depends?\s+on\s+([^.\n]+)/gi,
|
|
133
|
+
/after\s+([^.\n]+)/gi,
|
|
134
|
+
/blocked\s+by\s+([^.\n]+)/gi,
|
|
135
|
+
/requires?\s+([^.\n]+)/gi,
|
|
136
|
+
];
|
|
137
|
+
for (const pattern of dependencyStatements) {
|
|
138
|
+
let match;
|
|
139
|
+
while ((match = pattern.exec(body)) !== null) {
|
|
140
|
+
const statement = match[1];
|
|
141
|
+
const issueRefs = statement.matchAll(/#(\d+)/g);
|
|
142
|
+
for (const ref of issueRefs) {
|
|
143
|
+
const num = parseInt(ref[1], 10);
|
|
144
|
+
if (validNumbers.includes(num) && num !== issue.number) {
|
|
145
|
+
dependencies.add(num);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return Array.from(dependencies);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Extract affected file paths from issue body.
|
|
154
|
+
*/
|
|
155
|
+
extractAffectedPaths(issue) {
|
|
156
|
+
if (!issue.body)
|
|
157
|
+
return [];
|
|
158
|
+
const paths = new Set();
|
|
159
|
+
const pathPattern = /`((?:src|lib|app|packages?)\/[^`]+\.[a-z]+)`/gi;
|
|
160
|
+
let match;
|
|
161
|
+
while ((match = pathPattern.exec(issue.body)) !== null) {
|
|
162
|
+
paths.add(match[1]);
|
|
163
|
+
}
|
|
164
|
+
return Array.from(paths);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=issue-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue-analyzer.js","sourceRoot":"","sources":["../../src/analysis/issue-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-parser.d.ts","sourceRoot":"","sources":["../../src/analysis/plan-parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgDjD,qBAAa,UAAU;IACrB;;OAEG;IACG,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CA6E3D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { query } from '@anthropic-ai/claude-code';
|
|
3
|
+
const PLAN_ANALYSIS_PROMPT = `Analyze this plan and break it into discrete, implementable work items.
|
|
4
|
+
|
|
5
|
+
## Plan
|
|
6
|
+
|
|
7
|
+
{{plan}}
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Your Task
|
|
12
|
+
|
|
13
|
+
Break this plan into discrete work items that can be implemented independently (but may have dependencies on each other).
|
|
14
|
+
|
|
15
|
+
For each work item, provide:
|
|
16
|
+
1. **id**: Sequential number starting from 1
|
|
17
|
+
2. **title**: Short descriptive title
|
|
18
|
+
3. **body**: Full implementation details including:
|
|
19
|
+
- What to create/modify
|
|
20
|
+
- Specific file paths
|
|
21
|
+
- Function signatures or interfaces
|
|
22
|
+
- Testing instructions
|
|
23
|
+
- Acceptance criteria
|
|
24
|
+
4. **dependencies**: IDs of work items that MUST be completed before this one
|
|
25
|
+
|
|
26
|
+
Respond with ONLY a JSON array (no markdown, no explanation):
|
|
27
|
+
[
|
|
28
|
+
{
|
|
29
|
+
"id": 1,
|
|
30
|
+
"title": "Initialize project",
|
|
31
|
+
"body": "Create the project structure...\\n\\n## Implementation\\n...",
|
|
32
|
+
"dependencies": []
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"id": 2,
|
|
36
|
+
"title": "Create utilities",
|
|
37
|
+
"body": "Create utility functions...\\n\\n**Depends on #1**\\n\\n## Implementation\\n...",
|
|
38
|
+
"dependencies": [1]
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
Rules:
|
|
43
|
+
- Each work item should be self-contained with all context needed to implement it
|
|
44
|
+
- Include "**Depends on #N**" in the body text for any dependencies
|
|
45
|
+
- Work items should be small enough to implement in one session
|
|
46
|
+
- Include specific file paths, function signatures, and acceptance criteria
|
|
47
|
+
- Respond with ONLY valid JSON, nothing else`;
|
|
48
|
+
export class PlanParser {
|
|
49
|
+
/**
|
|
50
|
+
* Parse a plan into discrete work items with dependencies.
|
|
51
|
+
*/
|
|
52
|
+
async parse(planContent) {
|
|
53
|
+
const prompt = PLAN_ANALYSIS_PROMPT.replace('{{plan}}', planContent);
|
|
54
|
+
console.log(chalk.gray(' Sending plan to Claude for analysis...'));
|
|
55
|
+
try {
|
|
56
|
+
const iterator = query({
|
|
57
|
+
prompt,
|
|
58
|
+
options: {
|
|
59
|
+
maxTurns: 1,
|
|
60
|
+
allowedTools: [],
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
let responseText = '';
|
|
64
|
+
for await (const message of iterator) {
|
|
65
|
+
const msg = message;
|
|
66
|
+
if (msg.type === 'assistant') {
|
|
67
|
+
const assistantMsg = msg.message;
|
|
68
|
+
if (assistantMsg?.content && Array.isArray(assistantMsg.content)) {
|
|
69
|
+
for (const block of assistantMsg.content) {
|
|
70
|
+
if (typeof block === 'object' && block && 'type' in block && block.type === 'text' && 'text' in block) {
|
|
71
|
+
responseText += String(block.text);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Parse JSON array from response
|
|
78
|
+
const jsonMatch = responseText.match(/\[[\s\S]*\]/);
|
|
79
|
+
if (!jsonMatch) {
|
|
80
|
+
throw new Error('No JSON array found in response');
|
|
81
|
+
}
|
|
82
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
83
|
+
const allIds = parsed.map(p => p.id);
|
|
84
|
+
// Convert to AnalyzedIssue format
|
|
85
|
+
const results = parsed.map(item => {
|
|
86
|
+
// Filter dependencies to only include valid IDs
|
|
87
|
+
const validDeps = item.dependencies.filter(d => allIds.includes(d) && d !== item.id);
|
|
88
|
+
const depsStr = validDeps.length > 0
|
|
89
|
+
? `depends on ${validDeps.map(d => `#${d}`).join(', ')}`
|
|
90
|
+
: 'no dependencies';
|
|
91
|
+
console.log(chalk.gray(` #${item.id}: ${item.title} (${depsStr})`));
|
|
92
|
+
return {
|
|
93
|
+
number: item.id,
|
|
94
|
+
title: item.title,
|
|
95
|
+
body: item.body,
|
|
96
|
+
state: 'open',
|
|
97
|
+
labels: [],
|
|
98
|
+
url: '',
|
|
99
|
+
htmlUrl: '',
|
|
100
|
+
affectedPaths: [],
|
|
101
|
+
dependencies: validDeps,
|
|
102
|
+
analyzedAt: new Date().toISOString(),
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new Error(`Failed to parse plan: ${error instanceof Error ? error.message : error}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=plan-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-parser.js","sourceRoot":"","sources":["../../src/analysis/plan-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { RunState } from '../types.js';
|
|
2
|
+
export interface LeftoverState {
|
|
3
|
+
hasLeftovers: boolean;
|
|
4
|
+
interruptedRuns: RunState[];
|
|
5
|
+
worktreeDirs: string[];
|
|
6
|
+
millhouseBranches: string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Detect leftover state from previous interrupted runs.
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectLeftoverState(basePath?: string): Promise<LeftoverState>;
|
|
12
|
+
/**
|
|
13
|
+
* Clean up all millhouse state - worktrees, branches, run files, and labels.
|
|
14
|
+
*/
|
|
15
|
+
export declare function cleanupAllState(basePath?: string): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Display the leftover state to the user.
|
|
18
|
+
*/
|
|
19
|
+
export declare function displayLeftoverState(state: LeftoverState): void;
|
|
20
|
+
//# sourceMappingURL=cleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../../src/cli/cleanup.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAO5C,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,QAAQ,EAAE,CAAC;IAC5B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,aAAa,CAAC,CAgElG;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFrF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CA2B/D"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { MILLHOUSE_LABELS } from '../types.js';
|
|
6
|
+
import { GitHubClient } from '../github/client.js';
|
|
7
|
+
const MILLHOUSE_DIR = '.millhouse';
|
|
8
|
+
const ALL_LABELS = Object.values(MILLHOUSE_LABELS);
|
|
9
|
+
/**
|
|
10
|
+
* Detect leftover state from previous interrupted runs.
|
|
11
|
+
*/
|
|
12
|
+
export async function detectLeftoverState(basePath = process.cwd()) {
|
|
13
|
+
const result = {
|
|
14
|
+
hasLeftovers: false,
|
|
15
|
+
interruptedRuns: [],
|
|
16
|
+
worktreeDirs: [],
|
|
17
|
+
millhouseBranches: [],
|
|
18
|
+
};
|
|
19
|
+
const millhouseDir = path.join(basePath, MILLHOUSE_DIR);
|
|
20
|
+
// Check for interrupted/running runs
|
|
21
|
+
const runsDir = path.join(millhouseDir, 'runs');
|
|
22
|
+
try {
|
|
23
|
+
const runFiles = await fs.readdir(runsDir);
|
|
24
|
+
for (const file of runFiles) {
|
|
25
|
+
if (file.endsWith('.json')) {
|
|
26
|
+
const content = await fs.readFile(path.join(runsDir, file), 'utf-8');
|
|
27
|
+
const run = JSON.parse(content);
|
|
28
|
+
if (run.status === 'running' || run.status === 'interrupted') {
|
|
29
|
+
result.interruptedRuns.push(run);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// No runs directory
|
|
36
|
+
}
|
|
37
|
+
// Check for worktree directories
|
|
38
|
+
const worktreesDir = path.join(millhouseDir, 'worktrees');
|
|
39
|
+
try {
|
|
40
|
+
const entries = await fs.readdir(worktreesDir);
|
|
41
|
+
for (const entry of entries) {
|
|
42
|
+
const fullPath = path.join(worktreesDir, entry);
|
|
43
|
+
const stat = await fs.stat(fullPath);
|
|
44
|
+
if (stat.isDirectory()) {
|
|
45
|
+
result.worktreeDirs.push(fullPath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// No worktrees directory
|
|
51
|
+
}
|
|
52
|
+
// Check for millhouse branches
|
|
53
|
+
try {
|
|
54
|
+
const branches = execSync('git branch --list "millhouse/*"', {
|
|
55
|
+
cwd: basePath,
|
|
56
|
+
encoding: 'utf-8',
|
|
57
|
+
}).trim();
|
|
58
|
+
if (branches) {
|
|
59
|
+
result.millhouseBranches = branches
|
|
60
|
+
.split('\n')
|
|
61
|
+
.map(b => b.trim().replace(/^\* /, ''))
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Git command failed
|
|
67
|
+
}
|
|
68
|
+
result.hasLeftovers =
|
|
69
|
+
result.interruptedRuns.length > 0 ||
|
|
70
|
+
result.worktreeDirs.length > 0 ||
|
|
71
|
+
result.millhouseBranches.length > 0;
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Clean up all millhouse state - worktrees, branches, run files, and labels.
|
|
76
|
+
*/
|
|
77
|
+
export async function cleanupAllState(basePath = process.cwd()) {
|
|
78
|
+
const millhouseDir = path.join(basePath, MILLHOUSE_DIR);
|
|
79
|
+
// Remove labels from issues in interrupted runs
|
|
80
|
+
try {
|
|
81
|
+
const githubClient = new GitHubClient();
|
|
82
|
+
const runsDir = path.join(millhouseDir, 'runs');
|
|
83
|
+
const runFiles = await fs.readdir(runsDir).catch(() => []);
|
|
84
|
+
const issueNumbers = new Set();
|
|
85
|
+
for (const file of runFiles) {
|
|
86
|
+
if (file.endsWith('.json')) {
|
|
87
|
+
const content = await fs.readFile(path.join(runsDir, file), 'utf-8');
|
|
88
|
+
const run = JSON.parse(content);
|
|
89
|
+
for (const issue of run.issues) {
|
|
90
|
+
issueNumbers.add(issue.number);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const issueNumber of issueNumbers) {
|
|
95
|
+
for (const label of ALL_LABELS) {
|
|
96
|
+
await githubClient.removeLabel(issueNumber, label).catch(() => { });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// GitHub client might fail if not in a repo, continue with local cleanup
|
|
102
|
+
}
|
|
103
|
+
// Remove all worktree directories
|
|
104
|
+
const worktreesDir = path.join(millhouseDir, 'worktrees');
|
|
105
|
+
try {
|
|
106
|
+
await fs.rm(worktreesDir, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Directory might not exist
|
|
110
|
+
}
|
|
111
|
+
// Prune git worktrees
|
|
112
|
+
try {
|
|
113
|
+
execSync('git worktree prune', { cwd: basePath, stdio: 'ignore' });
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Git command failed
|
|
117
|
+
}
|
|
118
|
+
// Delete all millhouse branches
|
|
119
|
+
try {
|
|
120
|
+
const branches = execSync('git branch --list "millhouse/*"', {
|
|
121
|
+
cwd: basePath,
|
|
122
|
+
encoding: 'utf-8',
|
|
123
|
+
}).trim();
|
|
124
|
+
if (branches) {
|
|
125
|
+
const branchList = branches
|
|
126
|
+
.split('\n')
|
|
127
|
+
.map(b => b.trim().replace(/^\* /, ''))
|
|
128
|
+
.filter(Boolean);
|
|
129
|
+
for (const branch of branchList) {
|
|
130
|
+
try {
|
|
131
|
+
execSync(`git branch -D "${branch}"`, { cwd: basePath, stdio: 'ignore' });
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Branch might be checked out or other issue
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// Git command failed
|
|
141
|
+
}
|
|
142
|
+
// Clear run state files
|
|
143
|
+
const runsDir = path.join(millhouseDir, 'runs');
|
|
144
|
+
try {
|
|
145
|
+
await fs.rm(runsDir, { recursive: true, force: true });
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Directory might not exist
|
|
149
|
+
}
|
|
150
|
+
// Clear worktrees.json
|
|
151
|
+
const worktreesFile = path.join(millhouseDir, 'worktrees.json');
|
|
152
|
+
try {
|
|
153
|
+
await fs.unlink(worktreesFile);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// File might not exist
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Display the leftover state to the user.
|
|
161
|
+
*/
|
|
162
|
+
export function displayLeftoverState(state) {
|
|
163
|
+
console.log(chalk.yellow('\n⚠️ Found leftover state from a previous run:\n'));
|
|
164
|
+
if (state.interruptedRuns.length > 0) {
|
|
165
|
+
console.log(chalk.gray(' Interrupted runs:'));
|
|
166
|
+
for (const run of state.interruptedRuns) {
|
|
167
|
+
const issueCount = run.issues.length;
|
|
168
|
+
const completed = run.completedIssues.length;
|
|
169
|
+
console.log(` - ${run.id} (${completed}/${issueCount} issues completed)`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (state.worktreeDirs.length > 0) {
|
|
173
|
+
console.log(chalk.gray(' Worktree directories:'));
|
|
174
|
+
for (const dir of state.worktreeDirs) {
|
|
175
|
+
console.log(` - ${path.basename(dir)}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (state.millhouseBranches.length > 0) {
|
|
179
|
+
console.log(chalk.gray(' Git branches:'));
|
|
180
|
+
for (const branch of state.millhouseBranches) {
|
|
181
|
+
console.log(` - ${branch}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
console.log('');
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../src/cli/cleanup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clean.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/clean.ts"],"names":[],"mappings":"AAOA,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBlD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import { detectLeftoverState, cleanupAllState, displayLeftoverState, } from '../cleanup.js';
|
|
3
|
+
export async function cleanCommand() {
|
|
4
|
+
const spinner = ora('Checking for leftover state...').start();
|
|
5
|
+
const leftoverState = await detectLeftoverState();
|
|
6
|
+
if (!leftoverState.hasLeftovers) {
|
|
7
|
+
spinner.succeed('Nothing to clean up');
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
spinner.stop();
|
|
11
|
+
displayLeftoverState(leftoverState);
|
|
12
|
+
const cleanSpinner = ora('Cleaning up...').start();
|
|
13
|
+
await cleanupAllState();
|
|
14
|
+
cleanSpinner.succeed('Cleaned up all millhouse state');
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=clean.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clean.js","sourceRoot":"","sources":["../../../src/cli/commands/clean.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,OAAO,GAAG,GAAG,CAAC,gCAAgC,CAAC,CAAC,KAAK,EAAE,CAAC;IAE9D,MAAM,aAAa,GAAG,MAAM,mBAAmB,EAAE,CAAC;IAElD,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC;QAChC,OAAO,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,IAAI,EAAE,CAAC;IACf,oBAAoB,CAAC,aAAa,CAAC,CAAC;IAEpC,MAAM,YAAY,GAAG,GAAG,CAAC,gBAAgB,CAAC,CAAC,KAAK,EAAE,CAAC;IACnD,MAAM,eAAe,EAAE,CAAC;IACxB,YAAY,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/resume.ts"],"names":[],"mappings":"AAcA,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4EhE"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { Orchestrator } from '../../core/orchestrator.js';
|
|
4
|
+
import { loadConfig } from '../../storage/config.js';
|
|
5
|
+
import { JsonStore } from '../../storage/json-store.js';
|
|
6
|
+
import { GitHubClient } from '../../github/client.js';
|
|
7
|
+
import { LabelManager } from '../../github/label-manager.js';
|
|
8
|
+
import { IssueDiscoverer } from '../../github/issue-discoverer.js';
|
|
9
|
+
import { IssueAnalyzer } from '../../analysis/issue-analyzer.js';
|
|
10
|
+
import { GraphBuilder } from '../../analysis/graph-builder.js';
|
|
11
|
+
import { WorktreeManager } from '../../execution/worktree-manager.js';
|
|
12
|
+
import { ClaudeRunner } from '../../execution/claude-runner.js';
|
|
13
|
+
import { Scheduler } from '../../core/scheduler.js';
|
|
14
|
+
export async function resumeCommand(runId) {
|
|
15
|
+
const spinner = ora('Loading run state...').start();
|
|
16
|
+
try {
|
|
17
|
+
const store = new JsonStore();
|
|
18
|
+
const runState = await store.getRun(runId);
|
|
19
|
+
if (!runState) {
|
|
20
|
+
spinner.fail(`Run not found: ${runId}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
if (runState.status === 'completed') {
|
|
24
|
+
spinner.fail('Run already completed');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
spinner.text = 'Loading configuration...';
|
|
28
|
+
const config = await loadConfig();
|
|
29
|
+
// Initialize components
|
|
30
|
+
spinner.text = 'Initializing components...';
|
|
31
|
+
const githubClient = new GitHubClient();
|
|
32
|
+
const labelManager = new LabelManager(githubClient);
|
|
33
|
+
const issueDiscoverer = new IssueDiscoverer(githubClient);
|
|
34
|
+
const issueAnalyzer = new IssueAnalyzer();
|
|
35
|
+
const graphBuilder = new GraphBuilder();
|
|
36
|
+
const worktreeManager = new WorktreeManager();
|
|
37
|
+
const claudeRunner = new ClaudeRunner(config);
|
|
38
|
+
// Create scheduler with previous concurrency
|
|
39
|
+
const scheduler = new Scheduler({
|
|
40
|
+
concurrency: config.execution.concurrency,
|
|
41
|
+
continueOnError: config.execution.continueOnError,
|
|
42
|
+
});
|
|
43
|
+
// Create orchestrator
|
|
44
|
+
const orchestrator = new Orchestrator({
|
|
45
|
+
config,
|
|
46
|
+
store,
|
|
47
|
+
githubClient,
|
|
48
|
+
labelManager,
|
|
49
|
+
issueDiscoverer,
|
|
50
|
+
issueAnalyzer,
|
|
51
|
+
graphBuilder,
|
|
52
|
+
worktreeManager,
|
|
53
|
+
claudeRunner,
|
|
54
|
+
scheduler,
|
|
55
|
+
});
|
|
56
|
+
spinner.succeed('Loaded');
|
|
57
|
+
// Show current state
|
|
58
|
+
console.log(chalk.blue(`\n📦 Resuming run: ${runId}`));
|
|
59
|
+
console.log(` Completed: ${runState.completedIssues.length}`);
|
|
60
|
+
console.log(` Failed: ${runState.failedIssues.length}`);
|
|
61
|
+
console.log(` Remaining: ${runState.issues.length - runState.completedIssues.length - runState.failedIssues.length}`);
|
|
62
|
+
// Resume execution
|
|
63
|
+
console.log(chalk.blue('\n🚀 Resuming execution...'));
|
|
64
|
+
const result = await orchestrator.resume(runState);
|
|
65
|
+
if (result.status === 'completed') {
|
|
66
|
+
console.log(chalk.green('\n✅ All issues completed successfully!'));
|
|
67
|
+
if (result.pullRequestUrl) {
|
|
68
|
+
console.log(chalk.blue(` Pull request: ${result.pullRequestUrl}`));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else if (result.status === 'failed') {
|
|
72
|
+
console.log(chalk.red(`\n❌ Run failed: ${result.error}`));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
spinner.fail('Error');
|
|
78
|
+
console.error(chalk.red(`\n${error instanceof Error ? error.message : error}`));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../src/cli/commands/resume.ts"],"names":[],"mappings":"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"}
|