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.
@@ -3,205 +3,236 @@
3
3
  * Tests all acceptance criteria for task-011
4
4
  */
5
5
 
6
- import { AgentClient } from './agent-client';
7
- import { loadConfig, resolveModelForPhase } from './config';
8
- import { isAgentAvailable } from './agent';
6
+ import { AgentClient } from './agent-client'
7
+ import { loadConfig, resolveModelForPhase } from './config'
8
+ import { isAgentAvailable } from './agent'
9
9
 
10
10
  async function runIntegrationTests() {
11
- console.log('๐Ÿงช Running comprehensive agent integration tests...\n');
12
-
13
- let passCount = 0;
14
- let failCount = 0;
15
-
11
+ console.log('๐Ÿงช Running comprehensive agent integration tests...\n')
12
+
13
+ let passCount = 0
14
+ let failCount = 0
15
+
16
16
  // Helper for test assertions
17
17
  function assert(condition: boolean, testName: string, details?: string) {
18
18
  if (condition) {
19
- console.log(`โœ“ ${testName}`);
20
- passCount++;
19
+ console.log(`โœ“ ${testName}`)
20
+ passCount++
21
21
  } else {
22
- console.error(`โœ— ${testName}`);
23
- if (details) console.error(` ${details}`);
24
- failCount++;
22
+ console.error(`โœ— ${testName}`)
23
+ if (details) console.error(` ${details}`)
24
+ failCount++
25
25
  }
26
26
  }
27
-
27
+
28
28
  try {
29
29
  // Load configuration
30
- const config = await loadConfig();
31
-
30
+ const config = await loadConfig()
31
+
32
32
  // Test 1: Verify agents are available
33
- console.log('1. Agent Availability\n');
34
- const opencodeAvailable = await isAgentAvailable('opencode');
35
- const claudeAvailable = await isAgentAvailable('claude');
36
- assert(opencodeAvailable || claudeAvailable, 'At least one agent available',
37
- `opencode: ${opencodeAvailable}, claude: ${claudeAvailable}`);
38
-
39
- const testAgent = opencodeAvailable ? 'opencode' : 'claude';
40
- console.log(` Using ${testAgent} for tests\n`);
41
-
33
+ console.log('1. Agent Availability\n')
34
+ const opencodeAvailable = await isAgentAvailable('opencode')
35
+ const claudeAvailable = await isAgentAvailable('claude')
36
+ assert(
37
+ opencodeAvailable || claudeAvailable,
38
+ 'At least one agent available',
39
+ `opencode: ${opencodeAvailable}, claude: ${claudeAvailable}`
40
+ )
41
+
42
+ const testAgent = opencodeAvailable ? 'opencode' : 'claude'
43
+ console.log(` Using ${testAgent} for tests\n`)
44
+
42
45
  // Test 2: Phase-specific model resolution
43
- console.log('2. Phase-Specific Model Configuration\n');
44
- const prdModel = resolveModelForPhase(config, 'prd');
45
- const prdToTasksModel = resolveModelForPhase(config, 'prdToTasks');
46
- const implementModel = resolveModelForPhase(config, 'implement');
47
- const reviewModel = resolveModelForPhase(config, 'review');
48
- const finalizeModel = resolveModelForPhase(config, 'finalize');
49
-
50
- assert(!!prdModel, 'PRD phase has model', prdModel);
51
- assert(!!prdToTasksModel, 'prdToTasks phase has model', prdToTasksModel);
52
- assert(!!implementModel, 'implement phase has model', implementModel);
53
- assert(!!reviewModel, 'review phase has model', reviewModel);
54
- assert(!!finalizeModel, 'finalize phase has model', finalizeModel);
55
- assert(prdModel.match(/^claude-(sonnet|opus)-\d+-\d{8}$/) !== null,
56
- 'Model name follows correct format', prdModel);
57
- console.log('');
58
-
46
+ console.log('2. Phase-Specific Model Configuration\n')
47
+ const prdModel = resolveModelForPhase(config, 'prd')
48
+ const prdToTasksModel = resolveModelForPhase(config, 'prdToTasks')
49
+ const implementModel = resolveModelForPhase(config, 'implement')
50
+ const reviewModel = resolveModelForPhase(config, 'review')
51
+ const finalizeModel = resolveModelForPhase(config, 'finalize')
52
+
53
+ assert(!!prdModel, 'PRD phase has model', prdModel)
54
+ assert(!!prdToTasksModel, 'prdToTasks phase has model', prdToTasksModel)
55
+ assert(!!implementModel, 'implement phase has model', implementModel)
56
+ assert(!!reviewModel, 'review phase has model', reviewModel)
57
+ assert(!!finalizeModel, 'finalize phase has model', finalizeModel)
58
+ assert(
59
+ prdModel.match(/^claude-(sonnet|opus)-\d+-\d{8}$/) !== null,
60
+ 'Model name follows correct format',
61
+ prdModel
62
+ )
63
+ console.log('')
64
+
59
65
  // Test 3: AgentClient basic functionality
60
- console.log('3. AgentClient Basic Functionality\n');
66
+ console.log('3. AgentClient Basic Functionality\n')
61
67
  const client = new AgentClient({
62
68
  agent: testAgent,
63
- model: prdModel
64
- });
65
-
66
- assert(!!client, 'AgentClient instantiates');
67
- assert(!!client.messages, 'AgentClient has messages API');
68
- assert(typeof client.messages.create === 'function', 'messages.create is a function');
69
- console.log('');
70
-
69
+ model: prdModel,
70
+ })
71
+
72
+ assert(!!client, 'AgentClient instantiates')
73
+ assert(!!client.messages, 'AgentClient has messages API')
74
+ assert(typeof client.messages.create === 'function', 'messages.create is a function')
75
+ console.log('')
76
+
71
77
  // Test 4: Simple message request
72
- console.log('4. Simple Message Request (Chat Functionality)\n');
78
+ console.log('4. Simple Message Request (Chat Functionality)\n')
73
79
  try {
74
80
  const response = await client.messages.create({
75
- messages: [{ role: 'user', content: 'Say "test passed" and nothing else.' }]
76
- });
77
-
78
- assert(!!response, 'Response received from agent');
79
- assert(Array.isArray(response.content), 'Response has content array');
80
- assert(response.content.length > 0, 'Content array not empty');
81
- assert(response.content[0]?.type === 'text', 'Content type is text');
82
- assert(!!response.content[0]?.text, 'Response has text content');
83
- console.log(` Response: "${response.content[0]?.text.substring(0, 50)}..."\n`);
81
+ messages: [{ role: 'user', content: 'Say "test passed" and nothing else.' }],
82
+ })
83
+
84
+ assert(!!response, 'Response received from agent')
85
+ assert(Array.isArray(response.content), 'Response has content array')
86
+ assert(response.content.length > 0, 'Content array not empty')
87
+ assert(response.content[0]?.type === 'text', 'Content type is text')
88
+ assert(!!response.content[0]?.text, 'Response has text content')
89
+ console.log(` Response: "${response.content[0]?.text.substring(0, 50)}..."\n`)
84
90
  } catch (error) {
85
- assert(false, 'Simple message request', error instanceof Error ? error.message : String(error));
86
- console.log('');
91
+ assert(
92
+ false,
93
+ 'Simple message request',
94
+ error instanceof Error ? error.message : String(error)
95
+ )
96
+ console.log('')
87
97
  }
88
-
98
+
89
99
  // Test 5: Message request with system prompt
90
- console.log('5. Message Request with System Prompt\n');
100
+ console.log('5. Message Request with System Prompt\n')
91
101
  try {
92
102
  const response = await client.messages.create({
93
103
  system: 'You are a helpful assistant. Be extremely concise.',
94
- messages: [{ role: 'user', content: 'What is 2+2? Answer with just the number.' }]
95
- });
96
-
97
- assert(!!response, 'Response received with system prompt');
98
- assert(!!response.content[0]?.text.includes('4'), 'Response contains expected content');
99
- console.log(` Response: "${response.content[0]?.text.substring(0, 50)}..."\n`);
104
+ messages: [{ role: 'user', content: 'What is 2+2? Answer with just the number.' }],
105
+ })
106
+
107
+ assert(!!response, 'Response received with system prompt')
108
+ assert(!!response.content[0]?.text.includes('4'), 'Response contains expected content')
109
+ console.log(` Response: "${response.content[0]?.text.substring(0, 50)}..."\n`)
100
110
  } catch (error) {
101
- assert(false, 'System prompt handling', error instanceof Error ? error.message : String(error));
102
- console.log('');
111
+ assert(
112
+ false,
113
+ 'System prompt handling',
114
+ error instanceof Error ? error.message : String(error)
115
+ )
116
+ console.log('')
103
117
  }
104
-
118
+
105
119
  // Test 6: Model parameter override
106
- console.log('6. Model Parameter Override\n');
120
+ console.log('6. Model Parameter Override\n')
107
121
  try {
108
122
  const response = await client.messages.create({
109
123
  model: prdModel, // Override model per request
110
- messages: [{ role: 'user', content: 'Say "model override works" and nothing else.' }]
111
- });
112
-
113
- assert(!!response, 'Request with model override succeeds');
114
- console.log('');
124
+ messages: [{ role: 'user', content: 'Say "model override works" and nothing else.' }],
125
+ })
126
+
127
+ assert(!!response, 'Request with model override succeeds')
128
+ console.log('')
115
129
  } catch (error) {
116
- assert(false, 'Model parameter override', error instanceof Error ? error.message : String(error));
117
- console.log('');
130
+ assert(
131
+ false,
132
+ 'Model parameter override',
133
+ error instanceof Error ? error.message : String(error)
134
+ )
135
+ console.log('')
118
136
  }
119
-
137
+
120
138
  // Test 7: Error handling - invalid model (should fail gracefully)
121
- console.log('7. Error Handling (Invalid Model)\n');
139
+ console.log('7. Error Handling (Invalid Model)\n')
122
140
  try {
123
141
  const badClient = new AgentClient({
124
142
  agent: testAgent,
125
- model: 'invalid-model-name'
126
- });
127
-
143
+ model: 'invalid-model-name',
144
+ })
145
+
128
146
  await badClient.messages.create({
129
- messages: [{ role: 'user', content: 'test' }]
130
- });
131
-
147
+ messages: [{ role: 'user', content: 'test' }],
148
+ })
149
+
132
150
  // If we get here, the agent didn't validate the model (some agents may not)
133
- console.log(' โ„น Agent accepted invalid model (agent-dependent behavior)\n');
134
- passCount++;
151
+ console.log(' โ„น Agent accepted invalid model (agent-dependent behavior)\n')
152
+ passCount++
135
153
  } catch (error) {
136
154
  // Expected to fail - this is correct behavior
137
- assert(true, 'Invalid model handled gracefully');
138
- console.log(` Expected error: ${error instanceof Error ? error.message.substring(0, 80) : String(error).substring(0, 80)}...\n`);
155
+ assert(true, 'Invalid model handled gracefully')
156
+ console.log(
157
+ ` Expected error: ${error instanceof Error ? error.message.substring(0, 80) : String(error).substring(0, 80)}...\n`
158
+ )
139
159
  }
140
-
160
+
141
161
  // Test 8: Multi-turn conversation
142
- console.log('8. Multi-Turn Conversation\n');
162
+ console.log('8. Multi-Turn Conversation\n')
143
163
  try {
144
164
  const response = await client.messages.create({
145
165
  messages: [
146
166
  { role: 'user', content: 'My favorite color is blue.' },
147
167
  { role: 'assistant', content: 'I understand your favorite color is blue.' },
148
- { role: 'user', content: 'What is my favorite color? Answer with just the color name.' }
149
- ]
150
- });
151
-
152
- assert(!!response, 'Multi-turn conversation succeeds');
153
- assert(!!response.content[0]?.text.toLowerCase().includes('blue'),
154
- 'Response references conversation history');
155
- console.log(` Response: "${response.content[0]?.text.substring(0, 50)}..."\n`);
168
+ { role: 'user', content: 'What is my favorite color? Answer with just the color name.' },
169
+ ],
170
+ })
171
+
172
+ assert(!!response, 'Multi-turn conversation succeeds')
173
+ assert(
174
+ !!response.content[0]?.text.toLowerCase().includes('blue'),
175
+ 'Response references conversation history'
176
+ )
177
+ console.log(` Response: "${response.content[0]?.text.substring(0, 50)}..."\n`)
156
178
  } catch (error) {
157
- assert(false, 'Multi-turn conversation', error instanceof Error ? error.message : String(error));
158
- console.log('');
179
+ assert(
180
+ false,
181
+ 'Multi-turn conversation',
182
+ error instanceof Error ? error.message : String(error)
183
+ )
184
+ console.log('')
159
185
  }
160
-
186
+
161
187
  // Test 9: Response format compatibility
162
- console.log('9. Response Format Compatibility (Anthropic SDK)\n');
188
+ console.log('9. Response Format Compatibility (Anthropic SDK)\n')
163
189
  try {
164
190
  const response = await client.messages.create({
165
- messages: [{ role: 'user', content: 'Hello' }]
166
- });
167
-
191
+ messages: [{ role: 'user', content: 'Hello' }],
192
+ })
193
+
168
194
  // Check Anthropic SDK response format
169
- assert(typeof response === 'object', 'Response is an object');
170
- assert('content' in response, 'Response has content property');
171
- assert(Array.isArray(response.content), 'content is an array');
172
- assert(!!response.content[0]?.type && response.content[0].type === 'text', 'content item has type property');
173
- assert(!!(response.content[0] && 'text' in response.content[0]), 'content item has text property');
174
- console.log('');
195
+ assert(typeof response === 'object', 'Response is an object')
196
+ assert('content' in response, 'Response has content property')
197
+ assert(Array.isArray(response.content), 'content is an array')
198
+ assert(
199
+ !!response.content[0]?.type && response.content[0].type === 'text',
200
+ 'content item has type property'
201
+ )
202
+ assert(
203
+ !!(response.content[0] && 'text' in response.content[0]),
204
+ 'content item has text property'
205
+ )
206
+ console.log('')
175
207
  } catch (error) {
176
- assert(false, 'Response format check', error instanceof Error ? error.message : String(error));
177
- console.log('');
208
+ assert(false, 'Response format check', error instanceof Error ? error.message : String(error))
209
+ console.log('')
178
210
  }
179
-
180
211
  } catch (error) {
181
- console.error('\nโŒ Fatal error during tests:');
182
- console.error(error);
183
- failCount++;
212
+ console.error('\nโŒ Fatal error during tests:')
213
+ console.error(error)
214
+ failCount++
184
215
  }
185
-
216
+
186
217
  // Summary
187
- console.log('\n' + '='.repeat(60));
188
- console.log('Test Summary');
189
- console.log('='.repeat(60));
190
- console.log(`โœ“ Passed: ${passCount}`);
191
- console.log(`โœ— Failed: ${failCount}`);
192
- console.log(`Total: ${passCount + failCount}`);
193
-
218
+ console.log('\n' + '='.repeat(60))
219
+ console.log('Test Summary')
220
+ console.log('='.repeat(60))
221
+ console.log(`โœ“ Passed: ${passCount}`)
222
+ console.log(`โœ— Failed: ${failCount}`)
223
+ console.log(`Total: ${passCount + failCount}`)
224
+
194
225
  if (failCount === 0) {
195
- console.log('\n๐ŸŽ‰ All tests passed! Agent integration is working correctly.\n');
196
- process.exit(0);
226
+ console.log('\n๐ŸŽ‰ All tests passed! Agent integration is working correctly.\n')
227
+ process.exit(0)
197
228
  } else {
198
- console.log('\nโš ๏ธ Some tests failed. Review the output above.\n');
199
- process.exit(1);
229
+ console.log('\nโš ๏ธ Some tests failed. Review the output above.\n')
230
+ process.exit(1)
200
231
  }
201
232
  }
202
233
 
203
234
  // Run tests
204
235
  runIntegrationTests().catch(error => {
205
- console.error('Test runner error:', error);
206
- process.exit(1);
207
- });
236
+ console.error('Test runner error:', error)
237
+ process.exit(1)
238
+ })
@@ -1,94 +1,94 @@
1
- import { describe, expect, test, beforeEach, mock } from 'bun:test';
2
- import { setVerbose, getVerbose, logVerbose, logVerboseError, log, logError } from './logger';
1
+ import { describe, expect, test, beforeEach, mock } from 'bun:test'
2
+ import { setVerbose, getVerbose, logVerbose, logVerboseError, log, logError } from './logger'
3
3
 
4
4
  // Mock console functions
5
- const originalLog = console.log;
6
- const originalError = console.error;
7
- let logCalls: string[] = [];
8
- let errorCalls: string[] = [];
5
+ const originalLog = console.log
6
+ const originalError = console.error
7
+ let logCalls: string[] = []
8
+ let errorCalls: string[] = []
9
9
 
10
10
  beforeEach(() => {
11
11
  // Reset verbose mode to false before each test
12
- setVerbose(false);
13
-
12
+ setVerbose(false)
13
+
14
14
  // Reset call tracking
15
- logCalls = [];
16
- errorCalls = [];
17
-
15
+ logCalls = []
16
+ errorCalls = []
17
+
18
18
  // Mock console functions
19
19
  console.log = mock((message: string) => {
20
- logCalls.push(message);
21
- });
22
-
20
+ logCalls.push(message)
21
+ })
22
+
23
23
  console.error = mock((message: string) => {
24
- errorCalls.push(message);
25
- });
26
- });
24
+ errorCalls.push(message)
25
+ })
26
+ })
27
27
 
28
28
  // Restore console functions after all tests
29
29
  process.on('exit', () => {
30
- console.log = originalLog;
31
- console.error = originalError;
32
- });
30
+ console.log = originalLog
31
+ console.error = originalError
32
+ })
33
33
 
34
34
  describe('logger', () => {
35
35
  test('setVerbose and getVerbose work correctly', () => {
36
- expect(getVerbose()).toBe(false);
37
-
38
- setVerbose(true);
39
- expect(getVerbose()).toBe(true);
40
-
41
- setVerbose(false);
42
- expect(getVerbose()).toBe(false);
43
- });
44
-
36
+ expect(getVerbose()).toBe(false)
37
+
38
+ setVerbose(true)
39
+ expect(getVerbose()).toBe(true)
40
+
41
+ setVerbose(false)
42
+ expect(getVerbose()).toBe(false)
43
+ })
44
+
45
45
  test('logVerbose only logs when verbose mode is enabled', () => {
46
46
  // Should not log when verbose is false
47
- setVerbose(false);
48
- logVerbose('test message');
49
- expect(logCalls).toEqual([]);
50
-
47
+ setVerbose(false)
48
+ logVerbose('test message')
49
+ expect(logCalls).toEqual([])
50
+
51
51
  // Should log when verbose is true
52
- setVerbose(true);
53
- logVerbose('verbose message');
54
- expect(logCalls).toEqual(['verbose message']);
55
- });
56
-
52
+ setVerbose(true)
53
+ logVerbose('verbose message')
54
+ expect(logCalls).toEqual(['verbose message'])
55
+ })
56
+
57
57
  test('logVerboseError only logs when verbose mode is enabled', () => {
58
58
  // Should not log when verbose is false
59
- setVerbose(false);
60
- logVerboseError('test error');
61
- expect(errorCalls).toEqual([]);
62
-
59
+ setVerbose(false)
60
+ logVerboseError('test error')
61
+ expect(errorCalls).toEqual([])
62
+
63
63
  // Should log when verbose is true
64
- setVerbose(true);
65
- logVerboseError('verbose error');
66
- expect(errorCalls).toEqual(['verbose error']);
67
- });
68
-
64
+ setVerbose(true)
65
+ logVerboseError('verbose error')
66
+ expect(errorCalls).toEqual(['verbose error'])
67
+ })
68
+
69
69
  test('log always logs regardless of verbose mode', () => {
70
70
  // Should log when verbose is false
71
- setVerbose(false);
72
- log('always log');
73
- expect(logCalls).toEqual(['always log']);
74
-
71
+ setVerbose(false)
72
+ log('always log')
73
+ expect(logCalls).toEqual(['always log'])
74
+
75
75
  // Reset and test with verbose true
76
- logCalls = [];
77
- setVerbose(true);
78
- log('always log verbose');
79
- expect(logCalls).toEqual(['always log verbose']);
80
- });
81
-
76
+ logCalls = []
77
+ setVerbose(true)
78
+ log('always log verbose')
79
+ expect(logCalls).toEqual(['always log verbose'])
80
+ })
81
+
82
82
  test('logError always logs regardless of verbose mode', () => {
83
83
  // Should log when verbose is false
84
- setVerbose(false);
85
- logError('always error');
86
- expect(errorCalls).toEqual(['always error']);
87
-
84
+ setVerbose(false)
85
+ logError('always error')
86
+ expect(errorCalls).toEqual(['always error'])
87
+
88
88
  // Reset and test with verbose true
89
- errorCalls = [];
90
- setVerbose(true);
91
- logError('always error verbose');
92
- expect(errorCalls).toEqual(['always error verbose']);
93
- });
94
- });
89
+ errorCalls = []
90
+ setVerbose(true)
91
+ logError('always error verbose')
92
+ expect(errorCalls).toEqual(['always error verbose'])
93
+ })
94
+ })
package/src/logger.ts CHANGED
@@ -3,14 +3,14 @@
3
3
  * Provides verbose/quiet logging controls
4
4
  */
5
5
 
6
- let isVerbose = false;
6
+ let isVerbose = false
7
7
 
8
8
  export function setVerbose(verbose: boolean): void {
9
- isVerbose = verbose;
9
+ isVerbose = verbose
10
10
  }
11
11
 
12
12
  export function getVerbose(): boolean {
13
- return isVerbose;
13
+ return isVerbose
14
14
  }
15
15
 
16
16
  /**
@@ -18,7 +18,7 @@ export function getVerbose(): boolean {
18
18
  */
19
19
  export function logVerbose(message: string): void {
20
20
  if (isVerbose) {
21
- console.log(message);
21
+ console.log(message)
22
22
  }
23
23
  }
24
24
 
@@ -27,7 +27,7 @@ export function logVerbose(message: string): void {
27
27
  */
28
28
  export function logVerboseError(message: string): void {
29
29
  if (isVerbose) {
30
- console.error(message);
30
+ console.error(message)
31
31
  }
32
32
  }
33
33
 
@@ -35,12 +35,12 @@ export function logVerboseError(message: string): void {
35
35
  * Always log - for critical messages regardless of verbose mode
36
36
  */
37
37
  export function log(message: string): void {
38
- console.log(message);
38
+ console.log(message)
39
39
  }
40
40
 
41
41
  /**
42
42
  * Always log error - for critical errors regardless of verbose mode
43
43
  */
44
44
  export function logError(message: string): void {
45
- console.error(message);
46
- }
45
+ console.error(message)
46
+ }