@blockspool/cli 0.4.1 → 0.4.3

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,295 @@
1
+ /**
2
+ * Formulas - User-defined repeatable sweep recipes
3
+ *
4
+ * A formula is a YAML config that defines what an auto run should
5
+ * look for and how to fix it. Formulas live in .blockspool/formulas/
6
+ * and can be invoked with --formula <name>.
7
+ *
8
+ * Example:
9
+ * blockspool solo auto --formula security-audit
10
+ */
11
+ import * as fs from 'node:fs';
12
+ import * as path from 'node:path';
13
+ // =============================================================================
14
+ // Built-in Formulas
15
+ // =============================================================================
16
+ export const BUILTIN_FORMULAS = [
17
+ {
18
+ name: 'security-audit',
19
+ description: 'Find and fix security vulnerabilities',
20
+ categories: ['security'],
21
+ minConfidence: 80,
22
+ prompt: [
23
+ 'Look for OWASP Top 10 vulnerabilities, insecure defaults,',
24
+ 'missing input validation, credential exposure, and injection risks.',
25
+ 'Focus on real vulnerabilities, not style issues.',
26
+ ].join(' '),
27
+ maxPrs: 10,
28
+ tags: ['security'],
29
+ },
30
+ {
31
+ name: 'test-coverage',
32
+ description: 'Add missing unit tests for untested code',
33
+ categories: ['test'],
34
+ minConfidence: 70,
35
+ prompt: [
36
+ 'Find functions and modules with no test coverage.',
37
+ 'Write focused unit tests with edge cases.',
38
+ 'Prioritize business logic over utility functions.',
39
+ ].join(' '),
40
+ maxPrs: 15,
41
+ tags: ['quality'],
42
+ },
43
+ {
44
+ name: 'type-safety',
45
+ description: 'Strengthen TypeScript types and remove any/unknown',
46
+ categories: ['types'],
47
+ minConfidence: 75,
48
+ prompt: [
49
+ 'Find uses of any, unknown, or weak typing.',
50
+ 'Add proper type annotations, interfaces, and type guards.',
51
+ 'Do not change runtime behavior.',
52
+ ].join(' '),
53
+ maxPrs: 10,
54
+ tags: ['quality'],
55
+ },
56
+ {
57
+ name: 'cleanup',
58
+ description: 'Remove dead code, unused imports, and stale comments',
59
+ categories: ['refactor'],
60
+ minConfidence: 85,
61
+ prompt: [
62
+ 'Find dead code, unused imports, unreachable branches,',
63
+ 'commented-out code, and stale TODO comments.',
64
+ 'Only remove things that are clearly unused.',
65
+ ].join(' '),
66
+ maxPrs: 10,
67
+ tags: ['cleanup'],
68
+ },
69
+ {
70
+ name: 'deep',
71
+ description: 'Find high-impact structural and architectural improvements',
72
+ categories: ['refactor', 'perf', 'security'],
73
+ minConfidence: 60,
74
+ model: 'opus',
75
+ maxPrs: 5,
76
+ prompt: [
77
+ 'Principal engineer architecture review. Ignore trivial issues.',
78
+ 'Focus on: leaky abstractions, silent error swallowing, coupling/circular deps,',
79
+ 'mixed concerns (business logic + I/O), algorithmic perf issues,',
80
+ 'missing security boundaries, brittle integration points.',
81
+ 'Prefer moderate/complex complexity. Set impact_score 1-10.',
82
+ ].join(' '),
83
+ tags: ['architecture', 'deep'],
84
+ },
85
+ {
86
+ name: 'docs',
87
+ description: 'Add or improve documentation for public APIs',
88
+ categories: ['docs'],
89
+ minConfidence: 70,
90
+ prompt: [
91
+ 'Find exported functions, classes, and types missing JSDoc.',
92
+ 'Add clear, concise documentation that explains the purpose,',
93
+ 'parameters, and return values. Do not over-document obvious code.',
94
+ ].join(' '),
95
+ maxPrs: 10,
96
+ tags: ['docs'],
97
+ },
98
+ {
99
+ name: 'docs-audit',
100
+ description: 'Find stale, inaccurate, or missing documentation across code and markdown',
101
+ scope: '.',
102
+ categories: ['docs'],
103
+ minConfidence: 70,
104
+ exclude: ['CLAUDE.md', '.claude/**'],
105
+ prompt: [
106
+ 'Cross-reference documentation files (README.md, CLAUDE.md, docs/*.md, CONTRIBUTING.md)',
107
+ 'against the actual codebase to find inaccuracies.',
108
+ 'Look for: CLI flags/options documented that no longer exist or have changed,',
109
+ 'features described that have been renamed or removed,',
110
+ 'setup instructions that reference old paths or commands,',
111
+ 'outdated architecture descriptions that no longer match the code,',
112
+ 'missing documentation for recently added features or flags.',
113
+ 'Read both the markdown files AND the source code they reference to verify accuracy.',
114
+ 'Each proposal should fix one specific doc file with concrete corrections.',
115
+ 'Do NOT add new documentation — only fix what is wrong or outdated.',
116
+ ].join(' '),
117
+ maxPrs: 10,
118
+ tags: ['docs', 'audit'],
119
+ },
120
+ ];
121
+ // =============================================================================
122
+ // Formula Loader
123
+ // =============================================================================
124
+ /**
125
+ * Load a formula by name.
126
+ *
127
+ * Search order:
128
+ * 1. .blockspool/formulas/<name>.yaml (or .yml)
129
+ * 2. Built-in formulas
130
+ *
131
+ * @returns The formula, or null if not found
132
+ */
133
+ export function loadFormula(name, repoPath) {
134
+ // Try user-defined formulas first
135
+ const userFormula = loadUserFormula(name, repoPath);
136
+ if (userFormula)
137
+ return userFormula;
138
+ // Fall back to built-in formulas
139
+ return BUILTIN_FORMULAS.find(f => f.name === name) ?? null;
140
+ }
141
+ /**
142
+ * List all available formulas (built-in + user-defined)
143
+ */
144
+ export function listFormulas(repoPath) {
145
+ const userFormulas = loadAllUserFormulas(repoPath);
146
+ // User formulas override built-in ones with the same name
147
+ const userNames = new Set(userFormulas.map(f => f.name));
148
+ const builtins = BUILTIN_FORMULAS.filter(f => !userNames.has(f.name));
149
+ return [...userFormulas, ...builtins];
150
+ }
151
+ /**
152
+ * Load a user-defined formula from .blockspool/formulas/
153
+ */
154
+ function loadUserFormula(name, repoPath) {
155
+ const dir = getFormulasDir(repoPath);
156
+ if (!dir)
157
+ return null;
158
+ for (const ext of ['.yaml', '.yml']) {
159
+ const filePath = path.join(dir, `${name}${ext}`);
160
+ if (fs.existsSync(filePath)) {
161
+ return parseFormulaFile(filePath, name);
162
+ }
163
+ }
164
+ return null;
165
+ }
166
+ /**
167
+ * Load all user-defined formulas
168
+ */
169
+ function loadAllUserFormulas(repoPath) {
170
+ const dir = getFormulasDir(repoPath);
171
+ if (!dir || !fs.existsSync(dir))
172
+ return [];
173
+ const files = fs.readdirSync(dir).filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
174
+ const formulas = [];
175
+ for (const file of files) {
176
+ const name = path.basename(file, path.extname(file));
177
+ const formula = parseFormulaFile(path.join(dir, file), name);
178
+ if (formula)
179
+ formulas.push(formula);
180
+ }
181
+ return formulas;
182
+ }
183
+ /**
184
+ * Get the formulas directory path
185
+ */
186
+ function getFormulasDir(repoPath) {
187
+ const base = repoPath || process.cwd();
188
+ return path.join(base, '.blockspool', 'formulas');
189
+ }
190
+ /**
191
+ * Parse a YAML formula file.
192
+ * Uses a simple key: value parser to avoid adding a YAML dependency.
193
+ */
194
+ function parseFormulaFile(filePath, name) {
195
+ try {
196
+ const content = fs.readFileSync(filePath, 'utf-8');
197
+ const parsed = parseSimpleYaml(content);
198
+ return {
199
+ name,
200
+ description: parsed.description || `Formula: ${name}`,
201
+ scope: parsed.scope,
202
+ categories: parsed.categories ? parseStringList(parsed.categories) : undefined,
203
+ minConfidence: parsed.min_confidence ? parseInt(parsed.min_confidence, 10) : undefined,
204
+ prompt: parsed.prompt,
205
+ maxPrs: parsed.max_prs ? parseInt(parsed.max_prs, 10) : undefined,
206
+ maxTime: parsed.max_time,
207
+ focusAreas: parsed.focus_areas ? parseStringList(parsed.focus_areas) : undefined,
208
+ exclude: parsed.exclude ? parseStringList(parsed.exclude) : undefined,
209
+ useRoadmap: parsed.use_roadmap !== undefined ? parsed.use_roadmap === 'true' : undefined,
210
+ tags: parsed.tags ? parseStringList(parsed.tags) : undefined,
211
+ };
212
+ }
213
+ catch {
214
+ return null;
215
+ }
216
+ }
217
+ /**
218
+ * Simple YAML-like parser for flat key: value files.
219
+ * Handles single-line values and multi-line | blocks.
220
+ * Does NOT handle nested objects, anchors, or complex YAML features.
221
+ */
222
+ function parseSimpleYaml(content) {
223
+ const result = {};
224
+ const lines = content.split('\n');
225
+ let currentKey = null;
226
+ let multilineValue = [];
227
+ let multilineIndent = 0;
228
+ for (const line of lines) {
229
+ // Skip comments and empty lines (unless in multiline)
230
+ if (!currentKey && (line.trim().startsWith('#') || line.trim() === ''))
231
+ continue;
232
+ // Check for multiline continuation
233
+ if (currentKey) {
234
+ const indent = line.length - line.trimStart().length;
235
+ if (indent > multilineIndent && line.trim() !== '') {
236
+ multilineValue.push(line.trim());
237
+ continue;
238
+ }
239
+ else {
240
+ // End of multiline block
241
+ result[currentKey] = multilineValue.join(' ');
242
+ currentKey = null;
243
+ multilineValue = [];
244
+ }
245
+ }
246
+ // Parse key: value
247
+ const match = line.match(/^(\w[\w_-]*)\s*:\s*(.*)/);
248
+ if (match) {
249
+ const [, key, value] = match;
250
+ const trimmedValue = value.trim();
251
+ if (trimmedValue === '|' || trimmedValue === '>') {
252
+ // Start multiline block
253
+ currentKey = key;
254
+ multilineIndent = line.length - line.trimStart().length;
255
+ multilineValue = [];
256
+ }
257
+ else {
258
+ result[key] = trimmedValue;
259
+ }
260
+ }
261
+ }
262
+ // Flush remaining multiline
263
+ if (currentKey) {
264
+ result[currentKey] = multilineValue.join(' ');
265
+ }
266
+ return result;
267
+ }
268
+ /**
269
+ * Parse a YAML-style list string: "[a, b, c]" or "a, b, c" -> ["a", "b", "c"]
270
+ */
271
+ function parseStringList(value) {
272
+ // Handle YAML array syntax: [a, b, c]
273
+ const stripped = value.replace(/^\[/, '').replace(/\]$/, '');
274
+ return stripped.split(',').map(s => s.trim()).filter(s => s.length > 0);
275
+ }
276
+ /**
277
+ * Apply a formula's settings to auto options.
278
+ * Formula values override defaults but CLI flags take precedence.
279
+ */
280
+ export function applyFormula(formula, cliOptions) {
281
+ return {
282
+ // CLI flags override formula values
283
+ scope: cliOptions.scope || formula.scope || 'src',
284
+ types: cliOptions.types || formula.categories,
285
+ minConfidence: cliOptions.minConfidence ?? formula.minConfidence,
286
+ maxPrs: cliOptions.maxPrs ?? formula.maxPrs,
287
+ maxTime: cliOptions.maxTime || formula.maxTime,
288
+ exclude: cliOptions.exclude || formula.exclude,
289
+ noRoadmap: cliOptions.noRoadmap ?? (formula.useRoadmap === false ? true : undefined),
290
+ // Formula-only fields (no CLI override)
291
+ prompt: formula.prompt,
292
+ focusAreas: formula.focusAreas,
293
+ };
294
+ }
295
+ //# sourceMappingURL=formulas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formulas.js","sourceRoot":"","sources":["../../src/lib/formulas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Git service implementation for CLI
3
+ */
4
+ import type { GitService } from '@blockspool/core/services';
5
+ /**
6
+ * Create a GitService instance
7
+ */
8
+ export declare function createGitService(): GitService;
9
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAmD5D;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAM7C"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Git service implementation for CLI
3
+ */
4
+ import * as fs from 'node:fs';
5
+ import * as path from 'node:path';
6
+ import { execSync } from 'node:child_process';
7
+ /**
8
+ * Find git repository root from a path
9
+ */
10
+ async function findRepoRoot(startPath) {
11
+ let current = path.resolve(startPath);
12
+ while (current !== path.dirname(current)) {
13
+ if (fs.existsSync(path.join(current, '.git'))) {
14
+ return current;
15
+ }
16
+ current = path.dirname(current);
17
+ }
18
+ return null;
19
+ }
20
+ /**
21
+ * Get remote URL from git
22
+ */
23
+ async function getRemoteUrl(repoRoot) {
24
+ try {
25
+ const url = execSync('git remote get-url origin', {
26
+ cwd: repoRoot,
27
+ encoding: 'utf-8',
28
+ stdio: ['ignore', 'pipe', 'ignore'],
29
+ }).trim();
30
+ return url || null;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * Generate deterministic project ID from repo
38
+ */
39
+ function getProjectId(repoRoot, remoteUrl) {
40
+ const source = remoteUrl || repoRoot;
41
+ // Simple hash for deterministic ID
42
+ let hash = 0;
43
+ for (let i = 0; i < source.length; i++) {
44
+ const char = source.charCodeAt(i);
45
+ hash = ((hash << 5) - hash) + char;
46
+ hash = hash & hash; // Convert to 32bit integer
47
+ }
48
+ return `proj_${Math.abs(hash).toString(36)}`;
49
+ }
50
+ /**
51
+ * Create a GitService instance
52
+ */
53
+ export function createGitService() {
54
+ return {
55
+ findRepoRoot,
56
+ getRemoteUrl,
57
+ getProjectId,
58
+ };
59
+ }
60
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/lib/git.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C;;GAEG;AACH,KAAK,UAAU,YAAY,CAAC,SAAiB;IAC3C,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEtC,OAAO,OAAO,KAAK,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;YAC9C,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,YAAY,CAAC,QAAgB;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,CAAC,2BAA2B,EAAE;YAChD,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,GAAG,IAAI,IAAI,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,QAAgB,EAAE,SAAwB;IAC9D,MAAM,MAAM,GAAG,SAAS,IAAI,QAAQ,CAAC;IAErC,mCAAmC;IACnC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;QACnC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,2BAA2B;IACjD,CAAC;IAED,OAAO,QAAQ,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,YAAY;QACZ,YAAY;QACZ,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Project guidelines loader — loads CLAUDE.md or AGENTS.md for prompt injection.
3
+ *
4
+ * For Claude-based runs: searches for CLAUDE.md
5
+ * For Codex-based runs: searches for AGENTS.md
6
+ * Falls back to whichever exists if the preferred one is missing.
7
+ */
8
+ /**
9
+ * Loaded project guidelines with metadata.
10
+ */
11
+ export interface ProjectGuidelines {
12
+ content: string;
13
+ source: string;
14
+ loadedAt: number;
15
+ }
16
+ export type GuidelinesBackend = 'claude' | 'codex';
17
+ export interface GuidelinesOptions {
18
+ /** Which backend is running. Determines default file search order. */
19
+ backend?: GuidelinesBackend;
20
+ /** Auto-create baseline file if none found. */
21
+ autoCreate?: boolean;
22
+ /**
23
+ * Custom path (relative to repoRoot) to the guidelines file.
24
+ * Overrides the default CLAUDE.md / AGENTS.md search.
25
+ * Set to false to disable guidelines entirely.
26
+ */
27
+ customPath?: string | false | null;
28
+ }
29
+ /**
30
+ * Load project guidelines.
31
+ *
32
+ * Resolution order:
33
+ * 1. If customPath is false → disabled, return null
34
+ * 2. If customPath is a string → use that exact file
35
+ * 3. Otherwise → search default paths by backend (primary then fallback)
36
+ * 4. If nothing found and autoCreate → generate baseline
37
+ */
38
+ export declare function loadGuidelines(repoRoot: string, opts?: GuidelinesOptions): ProjectGuidelines | null;
39
+ /**
40
+ * Wrap guidelines in XML tags for prompt injection.
41
+ */
42
+ export declare function formatGuidelinesForPrompt(guidelines: ProjectGuidelines): string;
43
+ //# sourceMappingURL=guidelines.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guidelines.d.ts","sourceRoot":"","sources":["../../src/lib/guidelines.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAYnD,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,+CAA+C;IAC/C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,iBAAsB,GAC3B,iBAAiB,GAAG,IAAI,CAwB1B;AAkCD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,iBAAiB,GAAG,MAAM,CAO/E"}
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Project guidelines loader — loads CLAUDE.md or AGENTS.md for prompt injection.
3
+ *
4
+ * For Claude-based runs: searches for CLAUDE.md
5
+ * For Codex-based runs: searches for AGENTS.md
6
+ * Falls back to whichever exists if the preferred one is missing.
7
+ */
8
+ import * as fs from 'node:fs';
9
+ import * as path from 'node:path';
10
+ /**
11
+ * Search paths by backend, in priority order.
12
+ * Primary search uses the backend-appropriate file, fallback uses the other.
13
+ */
14
+ const CLAUDE_PATHS = ['CLAUDE.md'];
15
+ const CODEX_PATHS = ['AGENTS.md'];
16
+ const MAX_CHARS = 4000;
17
+ /**
18
+ * Load project guidelines.
19
+ *
20
+ * Resolution order:
21
+ * 1. If customPath is false → disabled, return null
22
+ * 2. If customPath is a string → use that exact file
23
+ * 3. Otherwise → search default paths by backend (primary then fallback)
24
+ * 4. If nothing found and autoCreate → generate baseline
25
+ */
26
+ export function loadGuidelines(repoRoot, opts = {}) {
27
+ const { backend = 'claude', autoCreate = false, customPath } = opts;
28
+ // Explicitly disabled
29
+ if (customPath === false)
30
+ return null;
31
+ // Custom path — single file, no fallback
32
+ if (typeof customPath === 'string') {
33
+ return readGuidelinesFile(repoRoot, customPath);
34
+ }
35
+ // Default search: primary paths then fallback
36
+ const primaryPaths = backend === 'codex' ? CODEX_PATHS : CLAUDE_PATHS;
37
+ const fallbackPaths = backend === 'codex' ? CLAUDE_PATHS : CODEX_PATHS;
38
+ const result = searchPaths(repoRoot, primaryPaths) ?? searchPaths(repoRoot, fallbackPaths);
39
+ if (result)
40
+ return result;
41
+ // Nothing found — auto-create if enabled
42
+ if (autoCreate) {
43
+ return createBaselineGuidelines(repoRoot, backend);
44
+ }
45
+ return null;
46
+ }
47
+ function readGuidelinesFile(repoRoot, rel) {
48
+ const full = path.join(repoRoot, rel);
49
+ if (!fs.existsSync(full))
50
+ return null;
51
+ try {
52
+ let content = fs.readFileSync(full, 'utf-8');
53
+ if (content.length > MAX_CHARS) {
54
+ content = content.slice(0, MAX_CHARS) + '\n\n[truncated]';
55
+ }
56
+ return { content, source: rel, loadedAt: Date.now() };
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }
62
+ function searchPaths(repoRoot, paths) {
63
+ for (const rel of paths) {
64
+ const full = path.join(repoRoot, rel);
65
+ if (fs.existsSync(full)) {
66
+ try {
67
+ let content = fs.readFileSync(full, 'utf-8');
68
+ if (content.length > MAX_CHARS) {
69
+ content = content.slice(0, MAX_CHARS) + '\n\n[truncated]';
70
+ }
71
+ return { content, source: rel, loadedAt: Date.now() };
72
+ }
73
+ catch {
74
+ // Unreadable — skip
75
+ }
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ /**
81
+ * Wrap guidelines in XML tags for prompt injection.
82
+ */
83
+ export function formatGuidelinesForPrompt(guidelines) {
84
+ return [
85
+ '<project-guidelines>',
86
+ `<!-- Source: ${guidelines.source} -->`,
87
+ guidelines.content,
88
+ '</project-guidelines>',
89
+ ].join('\n');
90
+ }
91
+ /**
92
+ * Generate a baseline guidelines file from project metadata.
93
+ * Writes AGENTS.md for codex, CLAUDE.md for claude.
94
+ * Returns the loaded guidelines, or null if creation fails.
95
+ */
96
+ function createBaselineGuidelines(repoRoot, backend) {
97
+ const filename = backend === 'codex' ? 'AGENTS.md' : 'CLAUDE.md';
98
+ const fullPath = path.join(repoRoot, filename);
99
+ // Don't overwrite existing files
100
+ if (fs.existsSync(fullPath))
101
+ return null;
102
+ const content = generateBaseline(repoRoot, backend);
103
+ try {
104
+ fs.writeFileSync(fullPath, content, 'utf-8');
105
+ return { content, source: filename, loadedAt: Date.now() };
106
+ }
107
+ catch {
108
+ // Can't write — not fatal
109
+ return null;
110
+ }
111
+ }
112
+ /**
113
+ * Build baseline guidelines content from project metadata.
114
+ */
115
+ function generateBaseline(repoRoot, backend) {
116
+ const projectName = path.basename(repoRoot);
117
+ const parts = [];
118
+ parts.push(`# ${projectName}`);
119
+ parts.push('');
120
+ // Detect project type from package.json
121
+ let description = '';
122
+ let hasTypeScript = false;
123
+ let testCmd = '';
124
+ let lintCmd = '';
125
+ let buildCmd = '';
126
+ const scripts = {};
127
+ try {
128
+ const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf-8'));
129
+ description = pkg.description || '';
130
+ Object.assign(scripts, pkg.scripts || {});
131
+ hasTypeScript = !!(pkg.devDependencies?.typescript ||
132
+ pkg.dependencies?.typescript);
133
+ if (scripts.test)
134
+ testCmd = `npm test`;
135
+ if (scripts.lint)
136
+ lintCmd = `npm run lint`;
137
+ if (scripts.typecheck || scripts['type-check']) {
138
+ lintCmd = lintCmd ? `${lintCmd} && npm run typecheck` : 'npm run typecheck';
139
+ }
140
+ if (scripts.build)
141
+ buildCmd = `npm run build`;
142
+ }
143
+ catch {
144
+ // No package.json — keep defaults
145
+ }
146
+ if (description) {
147
+ parts.push(description);
148
+ parts.push('');
149
+ }
150
+ // Conventions section
151
+ parts.push('## Conventions');
152
+ parts.push('');
153
+ if (hasTypeScript) {
154
+ parts.push('- This project uses TypeScript. Prefer strict types over `any`.');
155
+ }
156
+ parts.push('- Keep changes minimal and focused on the task at hand.');
157
+ parts.push('- Follow existing code style and patterns in the codebase.');
158
+ parts.push('- Do not introduce new dependencies without justification.');
159
+ parts.push('');
160
+ // Verification section
161
+ const verifyCommands = [];
162
+ if (lintCmd)
163
+ verifyCommands.push(lintCmd);
164
+ if (testCmd)
165
+ verifyCommands.push(testCmd);
166
+ if (buildCmd)
167
+ verifyCommands.push(buildCmd);
168
+ if (verifyCommands.length > 0) {
169
+ parts.push('## Verification');
170
+ parts.push('');
171
+ parts.push('After making changes, verify with:');
172
+ parts.push('');
173
+ for (const cmd of verifyCommands) {
174
+ parts.push(`\`\`\`bash`);
175
+ parts.push(cmd);
176
+ parts.push(`\`\`\``);
177
+ }
178
+ parts.push('');
179
+ }
180
+ // Detect monorepo
181
+ const hasWorkspaces = !!scripts['workspaces'] ||
182
+ fs.existsSync(path.join(repoRoot, 'pnpm-workspace.yaml')) ||
183
+ fs.existsSync(path.join(repoRoot, 'lerna.json'));
184
+ if (hasWorkspaces || fs.existsSync(path.join(repoRoot, 'packages'))) {
185
+ parts.push('## Structure');
186
+ parts.push('');
187
+ parts.push('This is a monorepo. When modifying code in one package, check for cross-package impacts.');
188
+ parts.push('');
189
+ }
190
+ const header = backend === 'codex'
191
+ ? '<!-- Generated by BlockSpool. Edit freely to customize agent behavior. -->'
192
+ : '<!-- Generated by BlockSpool. Edit freely to customize agent behavior. -->';
193
+ return header + '\n\n' + parts.join('\n');
194
+ }
195
+ //# sourceMappingURL=guidelines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guidelines.js","sourceRoot":"","sources":["../../src/lib/guidelines.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Logger implementation for CLI
3
+ */
4
+ import type { Logger } from '@blockspool/core/services';
5
+ export interface LoggerOptions {
6
+ verbose?: boolean;
7
+ quiet?: boolean;
8
+ }
9
+ /**
10
+ * Create a logger instance
11
+ */
12
+ export declare function createLogger(opts?: LoggerOptions): Logger;
13
+ /**
14
+ * Silent logger (for tests or quiet mode)
15
+ */
16
+ export declare const silentLogger: Logger;
17
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,GAAE,aAAkB,GAAG,MAAM,CA4B7D;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,MAK1B,CAAC"}