@blockspool/cli 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/dist/bin/blockspool.d.ts +16 -0
  2. package/dist/bin/blockspool.d.ts.map +1 -0
  3. package/dist/bin/blockspool.js +45 -0
  4. package/dist/bin/blockspool.js.map +1 -0
  5. package/dist/commands/solo-auto.d.ts +6 -0
  6. package/dist/commands/solo-auto.d.ts.map +1 -0
  7. package/dist/commands/solo-auto.js +418 -0
  8. package/dist/commands/solo-auto.js.map +1 -0
  9. package/dist/commands/solo-exec.d.ts +6 -0
  10. package/dist/commands/solo-exec.d.ts.map +1 -0
  11. package/dist/commands/solo-exec.js +656 -0
  12. package/dist/commands/solo-exec.js.map +1 -0
  13. package/dist/commands/solo-inspect.d.ts +6 -0
  14. package/dist/commands/solo-inspect.d.ts.map +1 -0
  15. package/dist/commands/solo-inspect.js +690 -0
  16. package/dist/commands/solo-inspect.js.map +1 -0
  17. package/dist/commands/solo-lifecycle.d.ts +6 -0
  18. package/dist/commands/solo-lifecycle.d.ts.map +1 -0
  19. package/dist/commands/solo-lifecycle.js +188 -0
  20. package/dist/commands/solo-lifecycle.js.map +1 -0
  21. package/dist/commands/solo-nudge.d.ts +6 -0
  22. package/dist/commands/solo-nudge.d.ts.map +1 -0
  23. package/dist/commands/solo-nudge.js +49 -0
  24. package/dist/commands/solo-nudge.js.map +1 -0
  25. package/dist/commands/solo-qa.d.ts +6 -0
  26. package/dist/commands/solo-qa.d.ts.map +1 -0
  27. package/dist/commands/solo-qa.js +254 -0
  28. package/dist/commands/solo-qa.js.map +1 -0
  29. package/dist/commands/solo.d.ts +11 -0
  30. package/dist/commands/solo.d.ts.map +1 -0
  31. package/dist/commands/solo.js +43 -0
  32. package/dist/commands/solo.js.map +1 -0
  33. package/dist/index.d.ts +18 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +18 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/lib/artifacts.d.ts +136 -0
  38. package/dist/lib/artifacts.d.ts.map +1 -0
  39. package/dist/lib/artifacts.js +146 -0
  40. package/dist/lib/artifacts.js.map +1 -0
  41. package/dist/lib/doctor.d.ts +45 -0
  42. package/dist/lib/doctor.d.ts.map +1 -0
  43. package/dist/lib/doctor.js +383 -0
  44. package/dist/lib/doctor.js.map +1 -0
  45. package/dist/lib/exec.d.ts +24 -0
  46. package/dist/lib/exec.d.ts.map +1 -0
  47. package/dist/lib/exec.js +295 -0
  48. package/dist/lib/exec.js.map +1 -0
  49. package/dist/lib/formulas.d.ts +78 -0
  50. package/dist/lib/formulas.d.ts.map +1 -0
  51. package/dist/lib/formulas.js +295 -0
  52. package/dist/lib/formulas.js.map +1 -0
  53. package/dist/lib/git.d.ts +9 -0
  54. package/dist/lib/git.d.ts.map +1 -0
  55. package/dist/lib/git.js +60 -0
  56. package/dist/lib/git.js.map +1 -0
  57. package/dist/lib/guidelines.d.ts +43 -0
  58. package/dist/lib/guidelines.d.ts.map +1 -0
  59. package/dist/lib/guidelines.js +195 -0
  60. package/dist/lib/guidelines.js.map +1 -0
  61. package/dist/lib/logger.d.ts +17 -0
  62. package/dist/lib/logger.d.ts.map +1 -0
  63. package/dist/lib/logger.js +42 -0
  64. package/dist/lib/logger.js.map +1 -0
  65. package/dist/lib/retention.d.ts +62 -0
  66. package/dist/lib/retention.d.ts.map +1 -0
  67. package/dist/lib/retention.js +285 -0
  68. package/dist/lib/retention.js.map +1 -0
  69. package/dist/lib/run-history.d.ts +52 -0
  70. package/dist/lib/run-history.d.ts.map +1 -0
  71. package/dist/lib/run-history.js +116 -0
  72. package/dist/lib/run-history.js.map +1 -0
  73. package/dist/lib/run-state.d.ts +58 -0
  74. package/dist/lib/run-state.d.ts.map +1 -0
  75. package/dist/lib/run-state.js +119 -0
  76. package/dist/lib/run-state.js.map +1 -0
  77. package/dist/lib/scope.d.ts +95 -0
  78. package/dist/lib/scope.d.ts.map +1 -0
  79. package/dist/lib/scope.js +291 -0
  80. package/dist/lib/scope.js.map +1 -0
  81. package/dist/lib/selection.d.ts +35 -0
  82. package/dist/lib/selection.d.ts.map +1 -0
  83. package/dist/lib/selection.js +110 -0
  84. package/dist/lib/selection.js.map +1 -0
  85. package/dist/lib/solo-auto.d.ts +87 -0
  86. package/dist/lib/solo-auto.d.ts.map +1 -0
  87. package/dist/lib/solo-auto.js +1230 -0
  88. package/dist/lib/solo-auto.js.map +1 -0
  89. package/dist/lib/solo-ci.d.ts +84 -0
  90. package/dist/lib/solo-ci.d.ts.map +1 -0
  91. package/dist/lib/solo-ci.js +300 -0
  92. package/dist/lib/solo-ci.js.map +1 -0
  93. package/dist/lib/solo-config.d.ts +155 -0
  94. package/dist/lib/solo-config.d.ts.map +1 -0
  95. package/dist/lib/solo-config.js +236 -0
  96. package/dist/lib/solo-config.js.map +1 -0
  97. package/dist/lib/solo-git.d.ts +44 -0
  98. package/dist/lib/solo-git.d.ts.map +1 -0
  99. package/dist/lib/solo-git.js +174 -0
  100. package/dist/lib/solo-git.js.map +1 -0
  101. package/dist/lib/solo-hints.d.ts +32 -0
  102. package/dist/lib/solo-hints.d.ts.map +1 -0
  103. package/dist/lib/solo-hints.js +98 -0
  104. package/dist/lib/solo-hints.js.map +1 -0
  105. package/dist/lib/solo-remote.d.ts +14 -0
  106. package/dist/lib/solo-remote.d.ts.map +1 -0
  107. package/dist/lib/solo-remote.js +48 -0
  108. package/dist/lib/solo-remote.js.map +1 -0
  109. package/dist/lib/solo-stdin.d.ts +13 -0
  110. package/dist/lib/solo-stdin.d.ts.map +1 -0
  111. package/dist/lib/solo-stdin.js +33 -0
  112. package/dist/lib/solo-stdin.js.map +1 -0
  113. package/dist/lib/solo-ticket.d.ts +213 -0
  114. package/dist/lib/solo-ticket.d.ts.map +1 -0
  115. package/dist/lib/solo-ticket.js +850 -0
  116. package/dist/lib/solo-ticket.js.map +1 -0
  117. package/dist/lib/solo-utils.d.ts +133 -0
  118. package/dist/lib/solo-utils.d.ts.map +1 -0
  119. package/dist/lib/solo-utils.js +300 -0
  120. package/dist/lib/solo-utils.js.map +1 -0
  121. package/dist/lib/spindle.d.ts +144 -0
  122. package/dist/lib/spindle.d.ts.map +1 -0
  123. package/dist/lib/spindle.js +388 -0
  124. package/dist/lib/spindle.js.map +1 -0
  125. package/dist/tui/app.d.ts +17 -0
  126. package/dist/tui/app.d.ts.map +1 -0
  127. package/dist/tui/app.js +139 -0
  128. package/dist/tui/app.js.map +1 -0
  129. package/dist/tui/index.d.ts +8 -0
  130. package/dist/tui/index.d.ts.map +1 -0
  131. package/dist/tui/index.js +7 -0
  132. package/dist/tui/index.js.map +1 -0
  133. package/dist/tui/poller.d.ts +42 -0
  134. package/dist/tui/poller.d.ts.map +1 -0
  135. package/dist/tui/poller.js +62 -0
  136. package/dist/tui/poller.js.map +1 -0
  137. package/dist/tui/screens/overview.d.ts +9 -0
  138. package/dist/tui/screens/overview.d.ts.map +1 -0
  139. package/dist/tui/screens/overview.js +189 -0
  140. package/dist/tui/screens/overview.js.map +1 -0
  141. package/dist/tui/state.d.ts +93 -0
  142. package/dist/tui/state.d.ts.map +1 -0
  143. package/dist/tui/state.js +169 -0
  144. package/dist/tui/state.js.map +1 -0
  145. package/dist/tui/types.d.ts +18 -0
  146. package/dist/tui/types.d.ts.map +1 -0
  147. package/dist/tui/types.js +5 -0
  148. package/dist/tui/types.js.map +1 -0
  149. package/package.json +1 -1
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Solo mode configuration
3
+ */
4
+ import { type DatabaseAdapter } from '@blockspool/core/db';
5
+ import type { ScoutDeps, ScoutProgress } from '@blockspool/core/services';
6
+ import type { TicketProposal } from '@blockspool/core/scout';
7
+ import type { SpindleConfig } from './spindle.js';
8
+ /**
9
+ * Retention configuration — caps on unbounded state accumulation.
10
+ * All values are item counts (not time-based), except maxStaleBranchDays.
11
+ */
12
+ export interface RetentionConfig {
13
+ /** Keep last N run folders in .blockspool/runs/ (default 50) */
14
+ maxRuns: number;
15
+ /** Keep last N lines in history.ndjson (default 100) */
16
+ maxHistoryEntries: number;
17
+ /** Keep newest N artifact files per run folder (default 20) */
18
+ maxArtifactsPerRun: number;
19
+ /** Keep last N archived spool files (default 5) */
20
+ maxSpoolArchives: number;
21
+ /** Max deferred proposals in run-state.json (default 20) */
22
+ maxDeferredProposals: number;
23
+ /** Hard-delete oldest completed tickets beyond this cap (default 200) */
24
+ maxCompletedTickets: number;
25
+ /** Cap file_edit_counts keys in spindle state (default 50) */
26
+ maxSpindleFileEditKeys: number;
27
+ /** Keep last N local blockspool/* branches (default 10) */
28
+ maxMergedBranches: number;
29
+ }
30
+ /**
31
+ * Default retention configuration — conservative values.
32
+ */
33
+ export declare const DEFAULT_RETENTION_CONFIG: RetentionConfig;
34
+ /**
35
+ * Auto configuration - the "trust ladder" settings
36
+ */
37
+ export interface AutoConfig {
38
+ allowCategories: string[];
39
+ blockCategories: string[];
40
+ minConfidence: number;
41
+ maxPrs: number;
42
+ maxFilesPerTicket: number;
43
+ maxLinesPerTicket: number;
44
+ draftPrs: boolean;
45
+ defaultScope: string;
46
+ docsAudit: boolean;
47
+ docsAuditInterval: number;
48
+ /** Pull from origin every N cycles to stay current with team changes (0 = disabled, default 5) */
49
+ pullEveryNCycles: number;
50
+ /** What to do when pull fails due to divergence: "halt" stops the session, "warn" logs and continues (default "halt") */
51
+ pullPolicy: 'halt' | 'warn';
52
+ /** Re-read guidelines file every N cycles to pick up changes (default 10, 0 = disabled) */
53
+ guidelinesRefreshCycles: number;
54
+ /** Auto-create a baseline guidelines file (AGENTS.md or CLAUDE.md) if none exists (default true) */
55
+ autoCreateGuidelines: boolean;
56
+ /**
57
+ * Custom path to guidelines file, relative to repo root.
58
+ * Overrides the default CLAUDE.md / AGENTS.md search.
59
+ * Set to false to disable guidelines entirely.
60
+ * Examples: "docs/GUIDELINES.md", "CONVENTIONS.md", false
61
+ */
62
+ guidelinesPath: string | false | null;
63
+ }
64
+ /**
65
+ * Default auto config - conservative "safe demo" settings
66
+ */
67
+ export declare const DEFAULT_AUTO_CONFIG: AutoConfig;
68
+ /**
69
+ * Solo config file structure
70
+ */
71
+ export interface SoloConfig {
72
+ version: number;
73
+ repoRoot: string;
74
+ createdAt: string;
75
+ dbPath: string;
76
+ qa?: {
77
+ commands: Array<{
78
+ name: string;
79
+ cmd: string;
80
+ cwd?: string;
81
+ timeoutSec?: number;
82
+ timeoutMs?: number;
83
+ }>;
84
+ retry?: {
85
+ enabled: boolean;
86
+ maxAttempts: number;
87
+ };
88
+ artifacts?: {
89
+ storeDir?: string;
90
+ maxLogBytes?: number;
91
+ tailBytes?: number;
92
+ };
93
+ };
94
+ allowedRemote?: string;
95
+ spindle?: Partial<SpindleConfig>;
96
+ auto?: Partial<AutoConfig>;
97
+ retention?: Partial<RetentionConfig>;
98
+ /** Max parallel tickets for plugin mode (default: 2, max: 5) */
99
+ pluginParallel?: number;
100
+ }
101
+ /**
102
+ * Detected QA command from project configuration
103
+ */
104
+ export interface DetectedQaCommand {
105
+ name: string;
106
+ cmd: string;
107
+ source: 'package.json' | 'detected';
108
+ }
109
+ /**
110
+ * Get the .blockspool directory path (repo-local or global)
111
+ */
112
+ export declare function getBlockspoolDir(repoRoot?: string): string;
113
+ /**
114
+ * Get database path
115
+ */
116
+ export declare function getDbPath(repoRoot?: string): string;
117
+ /**
118
+ * Check if solo mode is initialized for a repo
119
+ */
120
+ export declare function isInitialized(repoRoot: string): boolean;
121
+ /**
122
+ * Detect QA commands from project configuration
123
+ */
124
+ export declare function detectQaCommands(repoRoot: string): DetectedQaCommand[];
125
+ /**
126
+ * Initialize solo mode for a repository
127
+ */
128
+ export declare function initSolo(repoRoot: string): Promise<{
129
+ config: SoloConfig;
130
+ detectedQa: DetectedQaCommand[];
131
+ }>;
132
+ /**
133
+ * Load solo config
134
+ */
135
+ export declare function loadConfig(repoRoot: string): SoloConfig | null;
136
+ /**
137
+ * Get or create database adapter
138
+ */
139
+ export declare function getAdapter(repoRoot?: string): Promise<DatabaseAdapter>;
140
+ /**
141
+ * Create scout dependencies
142
+ */
143
+ export declare function createScoutDeps(db: DatabaseAdapter, opts?: {
144
+ verbose?: boolean;
145
+ quiet?: boolean;
146
+ }): ScoutDeps;
147
+ /**
148
+ * Format progress for display
149
+ */
150
+ export declare function formatProgress(progress: ScoutProgress): string;
151
+ /**
152
+ * Display a proposal summary
153
+ */
154
+ export declare function displayProposal(proposal: TicketProposal, index: number): void;
155
+ //# sourceMappingURL=solo-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solo-config.d.ts","sourceRoot":"","sources":["../../src/lib/solo-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Solo mode configuration
3
+ */
4
+ import * as path from 'node:path';
5
+ import * as fs from 'node:fs';
6
+ import chalk from 'chalk';
7
+ import { createSQLiteAdapter } from '@blockspool/sqlite';
8
+ import { getDefaultDatabaseUrl } from '@blockspool/core/db';
9
+ import { createGitService } from './git.js';
10
+ import { createLogger } from './logger.js';
11
+ /**
12
+ * Default retention configuration — conservative values.
13
+ */
14
+ export const DEFAULT_RETENTION_CONFIG = {
15
+ maxRuns: 50,
16
+ maxHistoryEntries: 100,
17
+ maxArtifactsPerRun: 20,
18
+ maxSpoolArchives: 5,
19
+ maxDeferredProposals: 20,
20
+ maxCompletedTickets: 200,
21
+ maxSpindleFileEditKeys: 50,
22
+ maxMergedBranches: 10,
23
+ };
24
+ /**
25
+ * Default auto config - conservative "safe demo" settings
26
+ */
27
+ export const DEFAULT_AUTO_CONFIG = {
28
+ allowCategories: ['refactor', 'test', 'docs', 'types', 'perf'],
29
+ blockCategories: ['security', 'deps', 'auth', 'config', 'migration'],
30
+ minConfidence: 70,
31
+ maxPrs: 3,
32
+ maxFilesPerTicket: 10,
33
+ maxLinesPerTicket: 300,
34
+ draftPrs: true,
35
+ defaultScope: 'src',
36
+ docsAudit: true,
37
+ docsAuditInterval: 3,
38
+ pullEveryNCycles: 5,
39
+ pullPolicy: 'halt',
40
+ guidelinesRefreshCycles: 10,
41
+ autoCreateGuidelines: true,
42
+ guidelinesPath: null,
43
+ };
44
+ /**
45
+ * Get the .blockspool directory path (repo-local or global)
46
+ */
47
+ export function getBlockspoolDir(repoRoot) {
48
+ if (repoRoot) {
49
+ return path.join(repoRoot, '.blockspool');
50
+ }
51
+ const home = process.env.HOME || process.env.USERPROFILE || '.';
52
+ return path.join(home, '.blockspool');
53
+ }
54
+ /**
55
+ * Get database path
56
+ */
57
+ export function getDbPath(repoRoot) {
58
+ const dir = getBlockspoolDir(repoRoot);
59
+ return path.join(dir, 'state.sqlite');
60
+ }
61
+ /**
62
+ * Check if solo mode is initialized for a repo
63
+ */
64
+ export function isInitialized(repoRoot) {
65
+ const configPath = path.join(getBlockspoolDir(repoRoot), 'config.json');
66
+ return fs.existsSync(configPath);
67
+ }
68
+ /**
69
+ * Detect QA commands from project configuration
70
+ */
71
+ export function detectQaCommands(repoRoot) {
72
+ const commands = [];
73
+ const packageJsonPath = path.join(repoRoot, 'package.json');
74
+ if (!fs.existsSync(packageJsonPath)) {
75
+ return commands;
76
+ }
77
+ try {
78
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
79
+ const scripts = packageJson.scripts || {};
80
+ const qaPatterns = [
81
+ { pattern: 'typecheck', priority: 1, name: 'typecheck' },
82
+ { pattern: 'type-check', priority: 1, name: 'typecheck' },
83
+ { pattern: 'check:types', priority: 1, name: 'typecheck' },
84
+ { pattern: 'lint', priority: 2, name: 'lint' },
85
+ { pattern: /^lint:.*/, priority: 2, name: 'lint' },
86
+ { pattern: 'check', priority: 3, name: 'check' },
87
+ { pattern: 'test', priority: 4, name: 'test' },
88
+ { pattern: 'test:unit', priority: 4, name: 'test:unit' },
89
+ { pattern: 'build', priority: 5, name: 'build' },
90
+ ];
91
+ const added = new Set();
92
+ for (const { pattern, name } of qaPatterns) {
93
+ for (const [scriptName, _scriptCmd] of Object.entries(scripts)) {
94
+ const matches = typeof pattern === 'string'
95
+ ? scriptName === pattern
96
+ : pattern.test(scriptName);
97
+ if (matches && !added.has(scriptName)) {
98
+ added.add(scriptName);
99
+ commands.push({
100
+ name: scriptName === name ? name : `${name} (${scriptName})`,
101
+ cmd: `npm run ${scriptName}`,
102
+ source: 'package.json',
103
+ });
104
+ }
105
+ }
106
+ }
107
+ const order = ['typecheck', 'lint', 'check', 'test', 'build'];
108
+ commands.sort((a, b) => {
109
+ const aIdx = order.findIndex(o => a.name.startsWith(o));
110
+ const bIdx = order.findIndex(o => b.name.startsWith(o));
111
+ return (aIdx === -1 ? 99 : aIdx) - (bIdx === -1 ? 99 : bIdx);
112
+ });
113
+ }
114
+ catch {
115
+ // Ignore JSON parse errors
116
+ }
117
+ return commands;
118
+ }
119
+ /**
120
+ * Initialize solo mode for a repository
121
+ */
122
+ export async function initSolo(repoRoot) {
123
+ const dir = getBlockspoolDir(repoRoot);
124
+ const configPath = path.join(dir, 'config.json');
125
+ const dbPath = getDbPath(repoRoot);
126
+ if (!fs.existsSync(dir)) {
127
+ fs.mkdirSync(dir, { recursive: true });
128
+ }
129
+ const detectedQa = detectQaCommands(repoRoot);
130
+ // Capture origin remote URL for safety validation
131
+ let allowedRemote;
132
+ try {
133
+ const { execSync } = await import('child_process');
134
+ allowedRemote = execSync('git remote get-url origin', { cwd: repoRoot, encoding: 'utf-8' }).trim();
135
+ }
136
+ catch {
137
+ // No remote configured yet — that's fine
138
+ }
139
+ const config = {
140
+ version: 1,
141
+ repoRoot,
142
+ createdAt: new Date().toISOString(),
143
+ dbPath,
144
+ ...(allowedRemote ? { allowedRemote } : {}),
145
+ };
146
+ if (detectedQa.length > 0) {
147
+ config.qa = {
148
+ commands: detectedQa.map(c => ({
149
+ name: c.name,
150
+ cmd: c.cmd,
151
+ })),
152
+ };
153
+ }
154
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
155
+ const gitignorePath = path.join(repoRoot, '.gitignore');
156
+ if (fs.existsSync(gitignorePath)) {
157
+ const content = fs.readFileSync(gitignorePath, 'utf-8');
158
+ if (!content.includes('.blockspool')) {
159
+ fs.appendFileSync(gitignorePath, '\n# BlockSpool local state\n.blockspool/\n');
160
+ }
161
+ }
162
+ return { config, detectedQa };
163
+ }
164
+ /**
165
+ * Load solo config
166
+ */
167
+ export function loadConfig(repoRoot) {
168
+ const configPath = path.join(getBlockspoolDir(repoRoot), 'config.json');
169
+ if (!fs.existsSync(configPath)) {
170
+ return null;
171
+ }
172
+ return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
173
+ }
174
+ /**
175
+ * Get or create database adapter
176
+ */
177
+ export async function getAdapter(repoRoot) {
178
+ const dbPath = repoRoot ? getDbPath(repoRoot) : getDefaultDatabaseUrl();
179
+ return createSQLiteAdapter({ url: dbPath });
180
+ }
181
+ /**
182
+ * Create scout dependencies
183
+ */
184
+ export function createScoutDeps(db, opts = {}) {
185
+ return {
186
+ db,
187
+ git: createGitService(),
188
+ logger: createLogger(opts),
189
+ };
190
+ }
191
+ /**
192
+ * Format progress for display
193
+ */
194
+ export function formatProgress(progress) {
195
+ switch (progress.phase) {
196
+ case 'init':
197
+ return chalk.gray(progress.message || 'Initializing...');
198
+ case 'scanning':
199
+ return chalk.gray(progress.message || 'Scanning files...');
200
+ case 'analyzing':
201
+ return chalk.gray(`Analyzing (${progress.filesScanned}/${progress.totalFiles} files, ` +
202
+ `${progress.proposalsFound} proposals)`);
203
+ case 'storing':
204
+ return chalk.gray(progress.message || 'Storing results...');
205
+ case 'complete':
206
+ return chalk.green(`Complete: ${progress.proposalsFound} proposals, ` +
207
+ `${progress.ticketsCreated} tickets created`);
208
+ default:
209
+ return '';
210
+ }
211
+ }
212
+ /**
213
+ * Display a proposal summary
214
+ */
215
+ export function displayProposal(proposal, index) {
216
+ const categoryColors = {
217
+ refactor: chalk.cyan,
218
+ docs: chalk.yellow,
219
+ test: chalk.green,
220
+ perf: chalk.magenta,
221
+ security: chalk.red,
222
+ };
223
+ const color = categoryColors[proposal.category] || chalk.white;
224
+ console.log();
225
+ console.log(chalk.bold(`${index + 1}. ${proposal.title}`));
226
+ const impactStr = proposal.impact_score !== null ? ` | impact ${proposal.impact_score}/10` : '';
227
+ console.log(` ${color(proposal.category)} | ` +
228
+ `${proposal.estimated_complexity} | ` +
229
+ `${proposal.confidence}% confidence${impactStr}`);
230
+ console.log(` ${chalk.gray(proposal.description.slice(0, 100))}` +
231
+ `${proposal.description.length > 100 ? '...' : ''}`);
232
+ console.log(` ${chalk.gray('Files:')} ` +
233
+ `${proposal.files.slice(0, 3).join(', ')}` +
234
+ `${proposal.files.length > 3 ? ` +${proposal.files.length - 3} more` : ''}`);
235
+ }
236
+ //# sourceMappingURL=solo-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solo-config.js","sourceRoot":"","sources":["../../src/lib/solo-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Solo mode git utilities
3
+ */
4
+ export declare function withGitMutex<T>(fn: () => Promise<T>): Promise<T>;
5
+ /**
6
+ * Async git command execution — does not block the event loop.
7
+ * Used instead of execSync to allow parallel ticket execution.
8
+ */
9
+ export declare function gitExec(cmd: string, opts: {
10
+ cwd: string;
11
+ encoding?: 'utf-8';
12
+ maxBuffer?: number;
13
+ stdio?: 'ignore';
14
+ }): Promise<string>;
15
+ /**
16
+ * Clean up worktree safely
17
+ */
18
+ export declare function cleanupWorktree(repoRoot: string, worktreePath: string): Promise<void>;
19
+ /**
20
+ * Create a milestone branch and persistent worktree for batch merging.
21
+ * Returns the branch name and worktree path.
22
+ */
23
+ export declare function createMilestoneBranch(repoRoot: string, baseBranch: string): Promise<{
24
+ milestoneBranch: string;
25
+ milestoneWorktreePath: string;
26
+ }>;
27
+ /**
28
+ * Merge a ticket branch into the milestone branch under git mutex.
29
+ * Returns success/conflict status.
30
+ */
31
+ export declare function mergeTicketToMilestone(repoRoot: string, ticketBranch: string, milestoneWorktreePath: string): Promise<{
32
+ success: boolean;
33
+ conflicted: boolean;
34
+ }>;
35
+ /**
36
+ * Push milestone branch and create a squash-merge draft PR to the base branch.
37
+ * Returns the PR URL.
38
+ */
39
+ export declare function pushAndPrMilestone(repoRoot: string, milestoneBranch: string, milestoneWorktreePath: string, milestoneNumber: number, ticketCount: number, summaries: string[]): Promise<string | undefined>;
40
+ /**
41
+ * Clean up the milestone worktree (but not the branch, which may have a PR).
42
+ */
43
+ export declare function cleanupMilestone(repoRoot: string): Promise<void>;
44
+ //# sourceMappingURL=solo-git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solo-git.d.ts","sourceRoot":"","sources":["../../src/lib/solo-git.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,wBAAgB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAKhE;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,QAAQ,CAAA;CAAE,GAC9E,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,iBAQ3E;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,qBAAqB,EAAE,MAAM,CAAA;CAAE,CAAC,CAmCrE;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,qBAAqB,EAAE,MAAM,GAC5B,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAqCpD;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,qBAAqB,EAAE,MAAM,EAC7B,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoC7B;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGtE"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Solo mode git utilities
3
+ */
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ /**
7
+ * Mutex for serializing git operations on the main repo.
8
+ * Git doesn't support concurrent index operations on the same repo,
9
+ * so worktree setup (fetch, branch, worktree add) must be serialized.
10
+ * Once worktrees are created, per-worktree git ops are safe in parallel.
11
+ */
12
+ let gitMutexPromise = Promise.resolve();
13
+ export function withGitMutex(fn) {
14
+ const prev = gitMutexPromise;
15
+ let resolve;
16
+ gitMutexPromise = new Promise((r) => { resolve = r; });
17
+ return prev.then(fn).finally(() => resolve());
18
+ }
19
+ /**
20
+ * Async git command execution — does not block the event loop.
21
+ * Used instead of execSync to allow parallel ticket execution.
22
+ */
23
+ export async function gitExec(cmd, opts) {
24
+ const { exec } = await import('child_process');
25
+ const { promisify } = await import('util');
26
+ const execPromise = promisify(exec);
27
+ const result = await execPromise(cmd, {
28
+ cwd: opts.cwd,
29
+ encoding: opts.encoding || 'utf-8',
30
+ maxBuffer: opts.maxBuffer || 10 * 1024 * 1024,
31
+ });
32
+ return result.stdout;
33
+ }
34
+ /**
35
+ * Clean up worktree safely
36
+ */
37
+ export async function cleanupWorktree(repoRoot, worktreePath) {
38
+ try {
39
+ if (fs.existsSync(worktreePath)) {
40
+ await gitExec(`git worktree remove --force "${worktreePath}"`, { cwd: repoRoot });
41
+ }
42
+ }
43
+ catch {
44
+ // Ignore cleanup errors
45
+ }
46
+ }
47
+ /**
48
+ * Create a milestone branch and persistent worktree for batch merging.
49
+ * Returns the branch name and worktree path.
50
+ */
51
+ export async function createMilestoneBranch(repoRoot, baseBranch) {
52
+ const ts = Date.now().toString(36);
53
+ const milestoneBranch = `blockspool/milestone-${ts}`;
54
+ const milestoneWorktreePath = path.join(repoRoot, '.blockspool', 'worktrees', '_milestone');
55
+ await withGitMutex(async () => {
56
+ // Ensure worktrees dir exists
57
+ const worktreesDir = path.join(repoRoot, '.blockspool', 'worktrees');
58
+ if (!fs.existsSync(worktreesDir)) {
59
+ fs.mkdirSync(worktreesDir, { recursive: true });
60
+ }
61
+ // Clean up any existing milestone worktree
62
+ if (fs.existsSync(milestoneWorktreePath)) {
63
+ await gitExec(`git worktree remove --force "${milestoneWorktreePath}"`, { cwd: repoRoot });
64
+ }
65
+ // Fetch latest
66
+ try {
67
+ await gitExec(`git fetch origin ${baseBranch}`, { cwd: repoRoot });
68
+ }
69
+ catch {
70
+ // Continue with what we have
71
+ }
72
+ // Create milestone branch from origin/baseBranch
73
+ try {
74
+ await gitExec(`git branch "${milestoneBranch}" "origin/${baseBranch}"`, { cwd: repoRoot });
75
+ }
76
+ catch {
77
+ // Branch may already exist
78
+ }
79
+ await gitExec(`git worktree add "${milestoneWorktreePath}" "${milestoneBranch}"`, { cwd: repoRoot });
80
+ });
81
+ return { milestoneBranch, milestoneWorktreePath };
82
+ }
83
+ /**
84
+ * Merge a ticket branch into the milestone branch under git mutex.
85
+ * Returns success/conflict status.
86
+ */
87
+ export async function mergeTicketToMilestone(repoRoot, ticketBranch, milestoneWorktreePath) {
88
+ return withGitMutex(async () => {
89
+ try {
90
+ await gitExec(`git merge --no-ff "${ticketBranch}" -m "Merge ${ticketBranch}"`, {
91
+ cwd: milestoneWorktreePath,
92
+ });
93
+ return { success: true, conflicted: false };
94
+ }
95
+ catch {
96
+ // Abort the failed merge
97
+ try {
98
+ await gitExec('git merge --abort', { cwd: milestoneWorktreePath });
99
+ }
100
+ catch {
101
+ // Ignore abort errors
102
+ }
103
+ // Retry: rebase ticket branch onto milestone, then merge
104
+ try {
105
+ const milestoneBranchName = (await gitExec('git rev-parse --abbrev-ref HEAD', {
106
+ cwd: milestoneWorktreePath,
107
+ })).trim();
108
+ // Rebase the ticket branch onto the current milestone tip
109
+ await gitExec(`git rebase "${milestoneBranchName}" "${ticketBranch}"`, {
110
+ cwd: repoRoot,
111
+ });
112
+ // Try merge again
113
+ await gitExec(`git merge --no-ff "${ticketBranch}" -m "Merge ${ticketBranch}"`, {
114
+ cwd: milestoneWorktreePath,
115
+ });
116
+ return { success: true, conflicted: false };
117
+ }
118
+ catch {
119
+ // Abort any in-progress rebase or merge
120
+ try {
121
+ await gitExec('git rebase --abort', { cwd: repoRoot });
122
+ }
123
+ catch { /* ignore */ }
124
+ try {
125
+ await gitExec('git merge --abort', { cwd: milestoneWorktreePath });
126
+ }
127
+ catch { /* ignore */ }
128
+ return { success: false, conflicted: true };
129
+ }
130
+ }
131
+ });
132
+ }
133
+ /**
134
+ * Push milestone branch and create a squash-merge draft PR to the base branch.
135
+ * Returns the PR URL.
136
+ */
137
+ export async function pushAndPrMilestone(repoRoot, milestoneBranch, milestoneWorktreePath, milestoneNumber, ticketCount, summaries) {
138
+ // Push safety: validate origin matches allowed remote
139
+ const { assertPushSafe } = await import('./solo-remote.js');
140
+ const { loadConfig } = await import('./solo-config.js');
141
+ const config = loadConfig(repoRoot);
142
+ await assertPushSafe(milestoneWorktreePath, config?.allowedRemote);
143
+ // Push the milestone branch
144
+ await gitExec(`git push -u origin "${milestoneBranch}"`, { cwd: milestoneWorktreePath });
145
+ // Build PR body
146
+ const bulletList = summaries.map(s => `- ${s}`).join('\n');
147
+ const title = `Milestone #${milestoneNumber}: ${ticketCount} improvements`;
148
+ const body = `## Milestone #${milestoneNumber}\n\n${ticketCount} tickets merged:\n\n${bulletList}\n\n---\n_Created by BlockSpool (milestone mode)_`;
149
+ try {
150
+ const prOutput = (await gitExec(`gh pr create --title "${title.replace(/"/g, '\\"')}" --body "${body.replace(/"/g, '\\"')}" --head "${milestoneBranch}" --draft`, { cwd: milestoneWorktreePath })).trim();
151
+ const urlMatch = prOutput.match(/https:\/\/github\.com\/[^\s]+/);
152
+ return urlMatch ? urlMatch[0] : undefined;
153
+ }
154
+ catch {
155
+ // PR might already exist for this branch — try to find it
156
+ try {
157
+ const existing = (await gitExec(`gh pr view "${milestoneBranch}" --json url --jq .url`, { cwd: milestoneWorktreePath })).trim();
158
+ if (existing.startsWith('https://'))
159
+ return existing;
160
+ }
161
+ catch {
162
+ // ignore
163
+ }
164
+ return undefined;
165
+ }
166
+ }
167
+ /**
168
+ * Clean up the milestone worktree (but not the branch, which may have a PR).
169
+ */
170
+ export async function cleanupMilestone(repoRoot) {
171
+ const milestoneWorktreePath = path.join(repoRoot, '.blockspool', 'worktrees', '_milestone');
172
+ await cleanupWorktree(repoRoot, milestoneWorktreePath);
173
+ }
174
+ //# sourceMappingURL=solo-git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solo-git.js","sourceRoot":"","sources":["../../src/lib/solo-git.ts"],"names":[],"mappings":"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"}