hone-ai 0.2.0 → 0.9.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/src/agent.ts CHANGED
@@ -1,21 +1,21 @@
1
- import { spawn, type ChildProcess } from 'child_process';
2
- import type { AgentType } from './config';
3
- import { exitWithError, ErrorMessages } from './errors';
4
- import { logVerbose, logVerboseError } from './logger';
1
+ import { spawn, type ChildProcess } from 'child_process'
2
+ import type { AgentType } from './config'
3
+ import { exitWithError, ErrorMessages } from './errors'
4
+ import { logVerbose, logVerboseError } from './logger'
5
5
 
6
6
  export interface SpawnAgentOptions {
7
- agent: AgentType;
8
- prompt: string;
9
- workingDir?: string;
10
- model?: string;
11
- silent?: boolean;
12
- timeout?: number; // Timeout in milliseconds
7
+ agent: AgentType
8
+ prompt: string
9
+ workingDir?: string
10
+ model?: string
11
+ silent?: boolean
12
+ timeout?: number // Timeout in milliseconds
13
13
  }
14
14
 
15
15
  export interface SpawnAgentResult {
16
- exitCode: number;
17
- stdout: string;
18
- stderr: string;
16
+ exitCode: number
17
+ stdout: string
18
+ stderr: string
19
19
  }
20
20
 
21
21
  /**
@@ -24,155 +24,155 @@ export interface SpawnAgentResult {
24
24
  * @returns Promise resolving to exit code and captured output
25
25
  */
26
26
  export async function spawnAgent(options: SpawnAgentOptions): Promise<SpawnAgentResult> {
27
- const { agent, prompt, workingDir = process.cwd(), model, silent = false, timeout } = options;
28
-
27
+ const { agent, prompt, workingDir = process.cwd(), model, silent = false, timeout } = options
28
+
29
29
  // Log agent spawn initiation
30
- logVerbose(`[Agent] Spawning ${agent} agent${model ? ` with model ${model}` : ''}`);
31
- logVerbose(`[Agent] Working directory: ${workingDir}`);
32
-
30
+ logVerbose(`[Agent] Spawning ${agent} agent${model ? ` with model ${model}` : ''}`)
31
+ logVerbose(`[Agent] Working directory: ${workingDir}`)
32
+
33
33
  // Build command and args based on agent type
34
34
  // opencode: opencode run [--model anthropic/<model>] "prompt text"
35
35
  // claude: claude -p "prompt text" [--model <model>]
36
- const command = agent === 'opencode' ? 'opencode' : 'claude';
37
- const args: string[] = [];
38
-
36
+ const command = agent === 'opencode' ? 'opencode' : 'claude'
37
+ const args: string[] = []
38
+
39
39
  if (agent === 'opencode') {
40
- args.push('run');
40
+ args.push('run')
41
41
  if (model) {
42
- args.push('--model', `anthropic/${model}`);
42
+ args.push('--model', `anthropic/${model}`)
43
43
  }
44
- args.push(prompt);
44
+ args.push(prompt)
45
45
  } else {
46
- args.push('-p', prompt);
46
+ args.push('-p', prompt)
47
47
  if (model) {
48
- args.push('--model', model);
48
+ args.push('--model', model)
49
49
  }
50
50
  }
51
-
51
+
52
52
  // Log command being executed
53
- const cmdString = `${command} ${args.slice(0, -1).join(' ')} "<prompt>"`;
54
- logVerbose(`[Agent] Command: ${cmdString}`);
55
-
53
+ const cmdString = `${command} ${args.slice(0, -1).join(' ')} "<prompt>"`
54
+ logVerbose(`[Agent] Command: ${cmdString}`)
55
+
56
56
  return new Promise((resolve, reject) => {
57
57
  const child: ChildProcess = spawn(command, args, {
58
58
  cwd: workingDir,
59
- stdio: ['inherit', 'pipe', 'pipe']
60
- });
61
-
62
- let stdout = '';
63
- let stderr = '';
64
- let isKilled = false;
65
- let timeoutId: NodeJS.Timeout | undefined;
66
-
59
+ stdio: ['inherit', 'pipe', 'pipe'],
60
+ })
61
+
62
+ let stdout = ''
63
+ let stderr = ''
64
+ let isKilled = false
65
+ let timeoutId: NodeJS.Timeout | undefined
66
+
67
67
  // Stream stdout to console and capture
68
68
  if (child.stdout) {
69
69
  child.stdout.on('data', (data: Buffer) => {
70
- const text = data.toString();
70
+ const text = data.toString()
71
71
  if (!silent) {
72
- process.stdout.write(text);
72
+ process.stdout.write(text)
73
73
  }
74
- stdout += text;
75
- });
74
+ stdout += text
75
+ })
76
76
  }
77
-
77
+
78
78
  // Stream stderr to console and capture
79
79
  if (child.stderr) {
80
80
  child.stderr.on('data', (data: Buffer) => {
81
- const text = data.toString();
81
+ const text = data.toString()
82
82
  if (!silent) {
83
- process.stderr.write(text);
83
+ process.stderr.write(text)
84
84
  }
85
- stderr += text;
86
- });
85
+ stderr += text
86
+ })
87
87
  }
88
-
88
+
89
89
  // Set up timeout if specified
90
90
  if (timeout && timeout > 0) {
91
91
  timeoutId = setTimeout(() => {
92
92
  if (!isKilled && child.pid) {
93
- logVerboseError(`[Agent] Process timed out after ${timeout}ms, killing...`);
94
- isKilled = true;
93
+ logVerboseError(`[Agent] Process timed out after ${timeout}ms, killing...`)
94
+ isKilled = true
95
95
  try {
96
- process.kill(-child.pid, 'SIGTERM');
96
+ process.kill(-child.pid, 'SIGTERM')
97
97
  } catch (err) {
98
- child.kill('SIGTERM');
98
+ child.kill('SIGTERM')
99
99
  }
100
100
  }
101
- }, timeout);
101
+ }, timeout)
102
102
  }
103
103
 
104
104
  // Handle SIGINT (ctrl+c) and SIGTERM to kill child process
105
105
  const handleSignal = (signal: NodeJS.Signals) => {
106
106
  if (!isKilled && child.pid) {
107
- isKilled = true;
107
+ isKilled = true
108
108
  if (timeoutId) {
109
- clearTimeout(timeoutId);
110
- timeoutId = undefined;
109
+ clearTimeout(timeoutId)
110
+ timeoutId = undefined
111
111
  }
112
112
  // Kill the child process group
113
113
  try {
114
- process.kill(-child.pid, signal);
114
+ process.kill(-child.pid, signal)
115
115
  } catch (err) {
116
116
  // Fallback to killing just the child
117
- child.kill(signal);
117
+ child.kill(signal)
118
118
  }
119
119
  }
120
- };
121
-
122
- process.on('SIGINT', handleSignal);
123
- process.on('SIGTERM', handleSignal);
124
-
120
+ }
121
+
122
+ process.on('SIGINT', handleSignal)
123
+ process.on('SIGTERM', handleSignal)
124
+
125
125
  // Handle process exit
126
126
  child.on('close', (code: number | null) => {
127
127
  // Clean up signal handlers and timeout
128
- process.off('SIGINT', handleSignal);
129
- process.off('SIGTERM', handleSignal);
128
+ process.off('SIGINT', handleSignal)
129
+ process.off('SIGTERM', handleSignal)
130
130
  if (timeoutId) {
131
- clearTimeout(timeoutId);
132
- timeoutId = undefined;
131
+ clearTimeout(timeoutId)
132
+ timeoutId = undefined
133
133
  }
134
-
135
- const exitCode = code ?? 1;
136
-
134
+
135
+ const exitCode = code ?? 1
136
+
137
137
  // Check if process was killed due to timeout
138
138
  if (isKilled && timeout) {
139
- logVerboseError(`[Agent] Process was terminated due to timeout (${timeout}ms)`);
139
+ logVerboseError(`[Agent] Process was terminated due to timeout (${timeout}ms)`)
140
140
  resolve({
141
141
  exitCode: 124, // Standard timeout exit code
142
142
  stdout,
143
- stderr: stderr + '\nProcess timed out'
144
- });
145
- return;
143
+ stderr: stderr + '\nProcess timed out',
144
+ })
145
+ return
146
146
  }
147
-
147
+
148
148
  // Log completion status
149
149
  if (exitCode === 0) {
150
- logVerbose(`[Agent] Process completed successfully (exit code 0)`);
150
+ logVerbose(`[Agent] Process completed successfully (exit code 0)`)
151
151
  } else {
152
- logVerboseError(`[Agent] Process exited with code ${exitCode}`);
152
+ logVerboseError(`[Agent] Process exited with code ${exitCode}`)
153
153
  }
154
-
154
+
155
155
  resolve({
156
156
  exitCode,
157
157
  stdout,
158
- stderr
159
- });
160
- });
161
-
158
+ stderr,
159
+ })
160
+ })
161
+
162
162
  // Handle spawn errors (e.g., command not found)
163
163
  child.on('error', (error: Error) => {
164
164
  // Clean up signal handlers and timeout
165
- process.off('SIGINT', handleSignal);
166
- process.off('SIGTERM', handleSignal);
165
+ process.off('SIGINT', handleSignal)
166
+ process.off('SIGTERM', handleSignal)
167
167
  if (timeoutId) {
168
- clearTimeout(timeoutId);
169
- timeoutId = undefined;
168
+ clearTimeout(timeoutId)
169
+ timeoutId = undefined
170
170
  }
171
-
172
- logVerboseError(`[Agent] Spawn error: ${error.message}`);
173
- reject(new Error(`Failed to spawn ${agent}: ${error.message}`));
174
- });
175
- });
171
+
172
+ logVerboseError(`[Agent] Spawn error: ${error.message}`)
173
+ reject(new Error(`Failed to spawn ${agent}: ${error.message}`))
174
+ })
175
+ })
176
176
  }
177
177
 
178
178
  /**
@@ -181,19 +181,19 @@ export async function spawnAgent(options: SpawnAgentOptions): Promise<SpawnAgent
181
181
  * @returns Promise resolving to true if agent is available
182
182
  */
183
183
  export async function isAgentAvailable(agent: AgentType): Promise<boolean> {
184
- const command = agent === 'opencode' ? 'opencode' : 'claude';
185
-
186
- return new Promise((resolve) => {
184
+ const command = agent === 'opencode' ? 'opencode' : 'claude'
185
+
186
+ return new Promise(resolve => {
187
187
  const child = spawn(command === 'opencode' ? 'which' : 'which', [command], {
188
- stdio: 'ignore'
189
- });
190
-
188
+ stdio: 'ignore',
189
+ })
190
+
191
191
  child.on('close', (code: number | null) => {
192
- resolve(code === 0);
193
- });
194
-
192
+ resolve(code === 0)
193
+ })
194
+
195
195
  child.on('error', () => {
196
- resolve(false);
197
- });
198
- });
196
+ resolve(false)
197
+ })
198
+ })
199
199
  }
@@ -0,0 +1,360 @@
1
+ import { describe, expect, test, beforeEach, afterEach, mock } from 'bun:test'
2
+ import { generateAgentsMd, AGENTS_DOCS_DIR } from './agents-md-generator'
3
+ import type { AgentsMdGeneratorOptions, GenerationResult } from './agents-md-generator'
4
+ import { existsSync, mkdirSync, rmSync } from 'fs'
5
+ import { join } from 'path'
6
+ import * as fs from 'fs/promises'
7
+
8
+ // Mock AgentClient
9
+ import { AgentClient } from './agent-client'
10
+
11
+ const mockAgentResponse = {
12
+ content: [
13
+ {
14
+ type: 'text' as const,
15
+ text: 'PRIMARY LANGUAGES: JavaScript, TypeScript\nUSAGE CONTEXT: TypeScript for main application code, JavaScript for configuration files',
16
+ },
17
+ ],
18
+ }
19
+
20
+ const mockAgentClient = {
21
+ messages: {
22
+ create: mock(async () => mockAgentResponse),
23
+ },
24
+ }
25
+
26
+ // Mock the AgentClient constructor
27
+ mock.module('./agent-client', () => ({
28
+ AgentClient: mock(() => mockAgentClient),
29
+ }))
30
+
31
+ // Test workspace setup
32
+ const TEST_WORKSPACE = join(process.cwd(), '.test-agents-md-workspace')
33
+ const originalCwd = process.cwd()
34
+
35
+ // Mock console and logger functions
36
+ const originalLog = console.log
37
+ const originalError = console.error
38
+ let logCalls: string[] = []
39
+ let errorCalls: string[] = []
40
+
41
+ beforeEach(() => {
42
+ // Reset call tracking
43
+ logCalls = []
44
+ errorCalls = []
45
+
46
+ // Create isolated test workspace
47
+ if (existsSync(TEST_WORKSPACE)) {
48
+ rmSync(TEST_WORKSPACE, { recursive: true, force: true })
49
+ }
50
+ mkdirSync(TEST_WORKSPACE, { recursive: true })
51
+
52
+ // Change to test workspace
53
+ process.chdir(TEST_WORKSPACE)
54
+
55
+ // Mock console functions
56
+ console.log = mock((message: string) => {
57
+ logCalls.push(message)
58
+ })
59
+
60
+ console.error = mock((message: string) => {
61
+ errorCalls.push(message)
62
+ })
63
+ })
64
+
65
+ afterEach(() => {
66
+ // Restore console functions
67
+ console.log = originalLog
68
+ console.error = originalError
69
+
70
+ // Return to original directory and clean up
71
+ process.chdir(originalCwd)
72
+ if (existsSync(TEST_WORKSPACE)) {
73
+ rmSync(TEST_WORKSPACE, { recursive: true, force: true })
74
+ }
75
+ })
76
+
77
+ describe('agents-md-generator', () => {
78
+ test('generateAgentsMd returns proper result structure', async () => {
79
+ const result: GenerationResult = await generateAgentsMd()
80
+
81
+ expect(result).toHaveProperty('success')
82
+ expect(result).toHaveProperty('filesCreated')
83
+ expect(typeof result.success).toBe('boolean')
84
+ expect(Array.isArray(result.filesCreated)).toBe(true)
85
+ })
86
+
87
+ test('generateAgentsMd generates content with basic project analysis', async () => {
88
+ const result: GenerationResult = await generateAgentsMd()
89
+
90
+ if (result.success && result.mainFilePath) {
91
+ expect(existsSync(result.mainFilePath)).toBe(true)
92
+ const content = await fs.readFile(result.mainFilePath, 'utf-8')
93
+ expect(content).toContain('# AGENTS.md')
94
+ expect(content).toContain('## Project Overview')
95
+ expect(content).toContain('## Build System')
96
+ }
97
+ })
98
+
99
+ test('generateAgentsMd accepts custom project path', async () => {
100
+ const options: AgentsMdGeneratorOptions = {
101
+ projectPath: process.cwd(),
102
+ }
103
+
104
+ const result = await generateAgentsMd(options)
105
+ expect(typeof result.success).toBe('boolean')
106
+ })
107
+
108
+ test('generateAgentsMd respects overwrite option when file exists', async () => {
109
+ // First generation should succeed
110
+ const firstResult = await generateAgentsMd()
111
+ expect(firstResult.success).toBe(true)
112
+
113
+ // Second generation without overwrite should fail
114
+ const secondResult = await generateAgentsMd()
115
+ expect(secondResult.success).toBe(false)
116
+ expect(secondResult.error?.message).toContain('already exists')
117
+
118
+ // Third generation with overwrite should succeed
119
+ const thirdResult = await generateAgentsMd({ overwrite: true })
120
+ expect(thirdResult.success).toBe(true)
121
+ })
122
+
123
+ test('generateAgentsMd handles errors gracefully', async () => {
124
+ // Test with invalid project path
125
+ const result = await generateAgentsMd({ projectPath: '/nonexistent/path' })
126
+
127
+ // Should handle errors gracefully and return error result
128
+ if (!result.success) {
129
+ expect(result.error).toBeInstanceOf(Error)
130
+ }
131
+ })
132
+
133
+ test('generateAgentsMd outputs expected log messages', async () => {
134
+ await generateAgentsMd()
135
+
136
+ expect(logCalls.some(msg => msg.includes('Phase 1: Project Analysis'))).toBe(true)
137
+ expect(logCalls.some(msg => msg.includes('✓ Generated AGENTS.md'))).toBe(true)
138
+ })
139
+
140
+ test(`generateAgentsMd creates ${AGENTS_DOCS_DIR}/ directory when content exceeds 100 lines`, async () => {
141
+ // Mock a response that will generate a very long output
142
+ const longMockResponse = {
143
+ content: [
144
+ {
145
+ type: 'text' as const,
146
+ text:
147
+ 'PRIMARY LANGUAGES: JavaScript, TypeScript, Python, Java, Go, Rust, PHP, Ruby, C++, C#, Swift, Kotlin, Scala, Clojure, Elixir, Erlang, Haskell, OCaml, F#, R, MATLAB, Lua, Perl, Shell\n'.repeat(
148
+ 20
149
+ ) +
150
+ 'This is a very detailed analysis that will definitely exceed the 100-line limit when combined with other sections. ' +
151
+ 'It includes extensive information about the project structure, dependencies, build systems, testing frameworks, and deployment strategies. ' +
152
+ `The content is intentionally verbose to trigger the ${AGENTS_DOCS_DIR}/ subdirectory creation logic.`,
153
+ },
154
+ ],
155
+ }
156
+
157
+ // Mock agent client to return long content
158
+ const longMockAgentClient = {
159
+ messages: {
160
+ create: mock(async () => longMockResponse),
161
+ },
162
+ }
163
+
164
+ // Replace the mock temporarily
165
+ const originalMock = mockAgentClient.messages.create
166
+ mockAgentClient.messages.create = longMockAgentClient.messages.create
167
+
168
+ const result = await generateAgentsMd()
169
+
170
+ // Restore original mock
171
+ mockAgentClient.messages.create = originalMock
172
+
173
+ expect(result.success).toBe(true)
174
+
175
+ // Check if ${AGENTS_DOCS_DIR}/ directory was created
176
+ if (result.agentsDirPath) {
177
+ expect(existsSync(result.agentsDirPath)).toBe(true)
178
+ expect(result.filesCreated.length).toBeGreaterThan(1) // Main file + detail files
179
+ expect(logCalls.some(msg => msg.includes('exceeds 100-line limit'))).toBe(true)
180
+ expect(logCalls.some(msg => msg.includes('✓ Created') && msg.includes('detail files'))).toBe(
181
+ true
182
+ )
183
+ }
184
+ })
185
+
186
+ test(`generateAgentsMd creates compact content with references when using ${AGENTS_DOCS_DIR}/ directory`, async () => {
187
+ // Create a package.json with many dependencies to ensure we have content
188
+ await fs.writeFile(
189
+ 'package.json',
190
+ JSON.stringify({
191
+ name: 'test-project',
192
+ scripts: { build: 'tsc', test: 'jest' },
193
+ dependencies: {
194
+ react: '^18.0.0',
195
+ typescript: '^5.0.0',
196
+ jest: '^29.0.0',
197
+ express: '^4.18.0',
198
+ },
199
+ }),
200
+ 'utf-8'
201
+ )
202
+
203
+ const result = await generateAgentsMd()
204
+ expect(result.success).toBe(true)
205
+
206
+ if (result.mainFilePath) {
207
+ const content = await fs.readFile(result.mainFilePath, 'utf-8')
208
+
209
+ // Should contain section headers
210
+ expect(content).toContain('## Project Overview')
211
+ expect(content).toContain('## Build System')
212
+
213
+ // If ${AGENTS_DOCS_DIR}/ directory was used, should contain references
214
+ if (result.agentsDirPath && existsSync(result.agentsDirPath)) {
215
+ expect(content).toContain(AGENTS_DOCS_DIR)
216
+ expect(content).toContain('for detailed information')
217
+
218
+ // Check that detail files were created
219
+ const detailFiles = ['languages.md', 'build.md']
220
+ for (const file of detailFiles) {
221
+ const detailPath = join(result.agentsDirPath, file)
222
+ if (existsSync(detailPath)) {
223
+ const detailContent = await fs.readFile(detailPath, 'utf-8')
224
+ expect(detailContent).toContain('# ')
225
+ expect(detailContent).toContain('part of the AGENTS.md documentation system')
226
+ }
227
+ }
228
+ }
229
+ }
230
+ })
231
+
232
+ test('generateAgentsMd handles project with TypeScript configuration', async () => {
233
+ // Create TypeScript project files
234
+ await fs.writeFile(
235
+ 'tsconfig.json',
236
+ JSON.stringify({
237
+ compilerOptions: {
238
+ target: 'ES2020',
239
+ module: 'commonjs',
240
+ strict: true,
241
+ },
242
+ }),
243
+ 'utf-8'
244
+ )
245
+
246
+ await fs.writeFile(
247
+ 'package.json',
248
+ JSON.stringify({
249
+ name: 'typescript-project',
250
+ scripts: { build: 'tsc' },
251
+ devDependencies: {
252
+ typescript: '^5.0.0',
253
+ },
254
+ }),
255
+ 'utf-8'
256
+ )
257
+
258
+ const result = await generateAgentsMd()
259
+ expect(result.success).toBe(true)
260
+
261
+ if (result.mainFilePath) {
262
+ const content = await fs.readFile(result.mainFilePath, 'utf-8')
263
+ expect(content).toContain('## Project Overview')
264
+ expect(content).toContain('## Build System')
265
+ }
266
+ })
267
+
268
+ test(`generateAgentsMd handles existing ${AGENTS_DOCS_DIR}/ directory properly`, async () => {
269
+ // Create existing ${AGENTS_DOCS_DIR}/ directory with a file
270
+ const agentsDir = join(process.cwd(), AGENTS_DOCS_DIR)
271
+ if (!existsSync(agentsDir)) {
272
+ mkdirSync(agentsDir, { recursive: true })
273
+ }
274
+ await fs.writeFile(join(agentsDir, 'existing.md'), 'Existing content', 'utf-8')
275
+
276
+ // First generation without overwrite
277
+ const result1 = await generateAgentsMd()
278
+ expect(result1.success).toBe(true)
279
+
280
+ // Second generation with overwrite
281
+ const result2 = await generateAgentsMd({ overwrite: true })
282
+ expect(result2.success).toBe(true)
283
+
284
+ // Verify existing file is still there (we don't delete unrelated files)
285
+ expect(existsSync(join(agentsDir, 'existing.md'))).toBe(true)
286
+ })
287
+
288
+ test(`generateAgentsMd creates ${AGENTS_DOCS_DIR}/ directory for complex projects`, async () => {
289
+ // Create a project with many sections to trigger ${AGENTS_DOCS_DIR}/ creation
290
+ await fs.writeFile(
291
+ 'package.json',
292
+ JSON.stringify({
293
+ name: 'complex-project',
294
+ scripts: {
295
+ build: 'tsc',
296
+ test: 'jest',
297
+ deploy: 'docker build',
298
+ lint: 'eslint',
299
+ },
300
+ dependencies: {
301
+ react: '^18.0.0',
302
+ express: '^4.18.0',
303
+ typescript: '^5.0.0',
304
+ jest: '^29.0.0',
305
+ eslint: '^8.0.0',
306
+ docker: '^1.0.0',
307
+ },
308
+ }),
309
+ 'utf-8'
310
+ )
311
+
312
+ // Create multiple config files
313
+ await fs.writeFile('Dockerfile', 'FROM node:18', 'utf-8')
314
+ await fs.writeFile('docker-compose.yml', 'version: "3"', 'utf-8')
315
+
316
+ const result = await generateAgentsMd()
317
+ expect(result.success).toBe(true)
318
+
319
+ // Should trigger ${AGENTS_DOCS_DIR}/ directory creation due to complexity
320
+ if (result.agentsDirPath) {
321
+ expect(existsSync(result.agentsDirPath)).toBe(true)
322
+ expect(result.filesCreated.length).toBeGreaterThan(1)
323
+ }
324
+ })
325
+
326
+ test('should generate AGENTS.md without unhelpful agent preambles', async () => {
327
+ // Test that generated AGENTS.md files don't contain "Based on my..." text
328
+ // This validates the fix for task-011/012 where agent preambles were cluttering the output
329
+
330
+ // Create minimal test project
331
+ await fs.writeFile('package.json', JSON.stringify({ name: 'test-project' }), 'utf-8')
332
+
333
+ const result = await generateAgentsMd({ overwrite: true })
334
+ expect(result.success).toBe(true)
335
+
336
+ if (result.success && result.mainFilePath) {
337
+ const content = await fs.readFile(result.mainFilePath, 'utf-8')
338
+
339
+ // Verify that unhelpful agent preambles are NOT in the AGENTS.md summary
340
+ // Comprehensive check for all common preamble patterns
341
+ expect(content).not.toMatch(/Based on my analysis.*?here's.*?/i)
342
+ expect(content).not.toMatch(/Based on my architectural analysis.*?/i)
343
+ expect(content).not.toMatch(/Based on my exploration.*?/i)
344
+ expect(content).not.toMatch(/Based on my comprehensive analysis.*?/i)
345
+ expect(content).not.toMatch(/Based on the.*?analysis.*?/i)
346
+ expect(content).not.toMatch(/Here's.*?analysis.*?:/i)
347
+ expect(content).not.toMatch(/Here's what I found.*?:/i)
348
+ expect(content).not.toMatch(/I've analyzed.*?:/i)
349
+ expect(content).not.toMatch(/I'll analyze.*?:/i)
350
+ expect(content).not.toMatch(/Looking at the project.*?:/i)
351
+ expect(content).not.toMatch(/After analyzing.*?:/i)
352
+ expect(content).not.toMatch(/Upon examination.*?:/i)
353
+ expect(content).not.toMatch(/Let me analyze.*?:/i)
354
+
355
+ // The content should have meaningful section headers
356
+ expect(content).toMatch(/## Project Overview/)
357
+ expect(content).toMatch(/## Build System/)
358
+ }
359
+ })
360
+ })