@howlil/ez-agents 3.4.1 → 3.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 (102) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +7 -18
  3. package/bin/install.js +52 -10
  4. package/commands/ez/join-discord.md +18 -18
  5. package/ez-agents/bin/lib/assistant-adapter.cjs +264 -264
  6. package/ez-agents/bin/lib/audit-exec.cjs +7 -2
  7. package/ez-agents/bin/lib/circuit-breaker.cjs +118 -118
  8. package/ez-agents/bin/lib/config.cjs +190 -190
  9. package/ez-agents/bin/lib/file-lock.cjs +236 -236
  10. package/ez-agents/bin/lib/frontmatter.cjs +299 -299
  11. package/ez-agents/bin/lib/fs-utils.cjs +153 -153
  12. package/ez-agents/bin/lib/git-utils.cjs +203 -203
  13. package/ez-agents/bin/lib/index.cjs +113 -113
  14. package/ez-agents/bin/lib/init.cjs +757 -757
  15. package/ez-agents/bin/lib/logger.cjs +47 -17
  16. package/ez-agents/bin/lib/milestone.cjs +241 -241
  17. package/ez-agents/bin/lib/model-provider.cjs +241 -241
  18. package/ez-agents/bin/lib/phase.cjs +925 -925
  19. package/ez-agents/bin/lib/planning-write.cjs +107 -107
  20. package/ez-agents/bin/lib/retry.cjs +119 -119
  21. package/ez-agents/bin/lib/roadmap.cjs +306 -306
  22. package/ez-agents/bin/lib/safe-exec.cjs +90 -4
  23. package/ez-agents/bin/lib/safe-path.cjs +130 -130
  24. package/ez-agents/bin/lib/state.cjs +736 -736
  25. package/ez-agents/bin/lib/temp-file.cjs +239 -239
  26. package/ez-agents/bin/lib/template.cjs +223 -223
  27. package/ez-agents/bin/lib/test-file-lock.cjs +112 -112
  28. package/ez-agents/bin/lib/test-graceful.cjs +93 -93
  29. package/ez-agents/bin/lib/test-logger.cjs +60 -60
  30. package/ez-agents/bin/lib/test-safe-exec.cjs +38 -38
  31. package/ez-agents/bin/lib/test-safe-path.cjs +33 -33
  32. package/ez-agents/bin/lib/test-temp-file.cjs +125 -125
  33. package/ez-agents/bin/lib/timeout-exec.cjs +63 -63
  34. package/ez-agents/bin/lib/verify.cjs +15 -1
  35. package/ez-agents/references/checkpoints.md +776 -776
  36. package/ez-agents/references/continuation-format.md +249 -249
  37. package/ez-agents/references/questioning.md +162 -162
  38. package/ez-agents/references/tdd.md +263 -263
  39. package/ez-agents/templates/codebase/concerns.md +310 -310
  40. package/ez-agents/templates/codebase/conventions.md +307 -307
  41. package/ez-agents/templates/codebase/integrations.md +280 -280
  42. package/ez-agents/templates/codebase/stack.md +186 -186
  43. package/ez-agents/templates/codebase/testing.md +480 -480
  44. package/ez-agents/templates/config.json +37 -37
  45. package/ez-agents/templates/continue-here.md +78 -78
  46. package/ez-agents/templates/milestone-archive.md +123 -123
  47. package/ez-agents/templates/milestone.md +115 -115
  48. package/ez-agents/templates/requirements.md +231 -231
  49. package/ez-agents/templates/research-project/ARCHITECTURE.md +204 -204
  50. package/ez-agents/templates/research-project/FEATURES.md +147 -147
  51. package/ez-agents/templates/research-project/PITFALLS.md +200 -200
  52. package/ez-agents/templates/research-project/STACK.md +120 -120
  53. package/ez-agents/templates/research-project/SUMMARY.md +170 -170
  54. package/ez-agents/templates/retrospective.md +54 -54
  55. package/ez-agents/templates/roadmap.md +202 -202
  56. package/ez-agents/templates/summary-minimal.md +41 -41
  57. package/ez-agents/templates/summary-standard.md +48 -48
  58. package/ez-agents/templates/summary.md +248 -248
  59. package/ez-agents/templates/user-setup.md +311 -311
  60. package/ez-agents/templates/verification-report.md +322 -322
  61. package/ez-agents/workflows/add-phase.md +112 -112
  62. package/ez-agents/workflows/add-tests.md +351 -351
  63. package/ez-agents/workflows/add-todo.md +158 -158
  64. package/ez-agents/workflows/audit-milestone.md +332 -332
  65. package/ez-agents/workflows/autonomous.md +743 -743
  66. package/ez-agents/workflows/check-todos.md +177 -177
  67. package/ez-agents/workflows/cleanup.md +152 -152
  68. package/ez-agents/workflows/complete-milestone.md +766 -766
  69. package/ez-agents/workflows/diagnose-issues.md +219 -219
  70. package/ez-agents/workflows/discovery-phase.md +289 -289
  71. package/ez-agents/workflows/discuss-phase.md +762 -762
  72. package/ez-agents/workflows/execute-phase.md +468 -468
  73. package/ez-agents/workflows/execute-plan.md +483 -483
  74. package/ez-agents/workflows/health.md +159 -159
  75. package/ez-agents/workflows/help.md +492 -492
  76. package/ez-agents/workflows/insert-phase.md +130 -130
  77. package/ez-agents/workflows/list-phase-assumptions.md +178 -178
  78. package/ez-agents/workflows/map-codebase.md +316 -316
  79. package/ez-agents/workflows/new-milestone.md +384 -384
  80. package/ez-agents/workflows/new-project.md +1113 -1113
  81. package/ez-agents/workflows/node-repair.md +92 -92
  82. package/ez-agents/workflows/pause-work.md +122 -122
  83. package/ez-agents/workflows/plan-milestone-gaps.md +274 -274
  84. package/ez-agents/workflows/plan-phase.md +651 -651
  85. package/ez-agents/workflows/progress.md +382 -382
  86. package/ez-agents/workflows/quick.md +610 -610
  87. package/ez-agents/workflows/remove-phase.md +155 -155
  88. package/ez-agents/workflows/research-phase.md +74 -74
  89. package/ez-agents/workflows/resume-project.md +307 -307
  90. package/ez-agents/workflows/set-profile.md +81 -81
  91. package/ez-agents/workflows/settings.md +242 -242
  92. package/ez-agents/workflows/stats.md +57 -57
  93. package/ez-agents/workflows/transition.md +544 -544
  94. package/ez-agents/workflows/ui-phase.md +290 -290
  95. package/ez-agents/workflows/ui-review.md +157 -157
  96. package/ez-agents/workflows/update.md +320 -320
  97. package/ez-agents/workflows/validate-phase.md +167 -167
  98. package/ez-agents/workflows/verify-phase.md +243 -243
  99. package/ez-agents/workflows/verify-work.md +584 -584
  100. package/package.json +2 -3
  101. package/scripts/build-hooks.js +43 -43
  102. package/scripts/run-tests.cjs +29 -29
@@ -1,241 +1,241 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * EZ Model Provider — Unified API for multiple AI providers
5
- *
6
- * Supports: Anthropic, Moonshot (Kimi), Alibaba (Qwen), OpenAI
7
- */
8
-
9
- const https = require('https');
10
- const { URL } = require('url');
11
- const Logger = require('./logger.cjs');
12
- const logger = new Logger();
13
-
14
- class ModelProvider {
15
- /**
16
- * Create model provider
17
- * @param {Object} config - Configuration
18
- */
19
- constructor(config) {
20
- this.provider = config.provider || 'anthropic';
21
- this.model = config.model || 'sonnet';
22
- this.apiKey = config.apiKey || process.env[`${this.provider.toUpperCase()}_API_KEY`];
23
-
24
- if (!this.apiKey && this.provider !== 'anthropic') {
25
- logger.warn('API key not configured', { provider: this.provider });
26
- }
27
- }
28
-
29
- /**
30
- * Helper for HTTP requests
31
- */
32
- _httpRequest(options, data) {
33
- return new Promise((resolve, reject) => {
34
- const req = https.request(options, (res) => {
35
- let body = '';
36
- res.on('data', (chunk) => body += chunk);
37
- res.on('end', () => {
38
- if (res.statusCode >= 200 && res.statusCode < 300) {
39
- try {
40
- resolve(JSON.parse(body));
41
- } catch (e) {
42
- resolve(body);
43
- }
44
- } else {
45
- reject(new Error(`HTTP ${res.statusCode}: ${body}`));
46
- }
47
- });
48
- });
49
- req.on('error', reject);
50
- if (data) req.write(JSON.stringify(data));
51
- req.end();
52
- });
53
- }
54
-
55
- /**
56
- * Send chat message
57
- * @param {Object[]} messages - Chat messages
58
- * @param {Object} options - Chat options
59
- * @returns {Promise<Object>} - Response
60
- */
61
- async chat(messages, options = {}) {
62
- logger.info('Chat request', {
63
- provider: this.provider,
64
- model: this.model,
65
- messageCount: messages.length
66
- });
67
-
68
- switch (this.provider) {
69
- case 'anthropic':
70
- return this._chatAnthropic(messages, options);
71
- case 'moonshot':
72
- return this._chatMoonshot(messages, options);
73
- case 'alibaba':
74
- case 'qwen':
75
- return this._chatQwen(messages, options);
76
- case 'openai':
77
- return this._chatOpenAI(messages, options);
78
- default:
79
- throw new Error(`Unsupported provider: ${this.provider}`);
80
- }
81
- }
82
-
83
- /**
84
- * Anthropic Claude API
85
- */
86
- async _chatAnthropic(messages, options) {
87
- // Anthropic usually requires their SDK or complex headers
88
- logger.debug('Anthropic chat', { model: this.model });
89
- return {
90
- content: '[Anthropic response placeholder - requires SDK]',
91
- provider: 'anthropic',
92
- model: this.model
93
- };
94
- }
95
-
96
- /**
97
- * Moonshot (Kimi) API
98
- */
99
- async _chatMoonshot(messages, options) {
100
- const modelName = this.model === 'sonnet' ? 'moonshot-v1-8k' : this.model;
101
- const data = {
102
- model: modelName,
103
- messages: messages,
104
- temperature: options.temperature || 0.3
105
- };
106
-
107
- const reqOptions = {
108
- hostname: 'api.moonshot.cn',
109
- path: '/v1/chat/completions',
110
- method: 'POST',
111
- headers: {
112
- 'Content-Type': 'application/json',
113
- 'Authorization': `Bearer ${this.apiKey}`
114
- }
115
- };
116
-
117
- try {
118
- const response = await this._httpRequest(reqOptions, data);
119
- return {
120
- content: response.choices[0].message.content,
121
- provider: 'moonshot',
122
- model: modelName
123
- };
124
- } catch (error) {
125
- logger.error('Moonshot API error', { error: error.message });
126
- throw error;
127
- }
128
- }
129
-
130
- /**
131
- * Alibaba Qwen API (DashScope)
132
- */
133
- async _chatQwen(messages, options) {
134
- // Map generic model names to Qwen specific ones
135
- let modelName = this.model;
136
- if (modelName === 'sonnet' || modelName === 'gpt-4') modelName = 'qwen-max';
137
- if (modelName === 'haiku' || modelName === 'gpt-3.5-turbo') modelName = 'qwen-plus';
138
-
139
- const data = {
140
- model: modelName,
141
- input: {
142
- messages: messages
143
- },
144
- parameters: {
145
- result_format: 'message',
146
- temperature: options.temperature || 0.3
147
- }
148
- };
149
-
150
- const reqOptions = {
151
- hostname: 'dashscope.aliyuncs.com',
152
- path: '/api/v1/services/aigc/text-generation/generation',
153
- method: 'POST',
154
- headers: {
155
- 'Content-Type': 'application/json',
156
- 'Authorization': `Bearer ${this.apiKey}`
157
- }
158
- };
159
-
160
- try {
161
- const response = await this._httpRequest(reqOptions, data);
162
- return {
163
- content: response.output.choices[0].message.content,
164
- provider: 'alibaba',
165
- model: modelName
166
- };
167
- } catch (error) {
168
- logger.error('Qwen API error', { error: error.message });
169
- throw error;
170
- }
171
- }
172
-
173
- /**
174
- * OpenAI API
175
- */
176
- async _chatOpenAI(messages, options) {
177
- const modelName = this.model === 'sonnet' ? 'gpt-4-turbo' : this.model;
178
- const data = {
179
- model: modelName,
180
- messages: messages,
181
- temperature: options.temperature || 0.3
182
- };
183
-
184
- const reqOptions = {
185
- hostname: 'api.openai.com',
186
- path: '/v1/chat/completions',
187
- method: 'POST',
188
- headers: {
189
- 'Content-Type': 'application/json',
190
- 'Authorization': `Bearer ${this.apiKey}`
191
- }
192
- };
193
-
194
- try {
195
- const response = await this._httpRequest(reqOptions, data);
196
- return {
197
- content: response.choices[0].message.content,
198
- provider: 'openai',
199
- model: modelName
200
- };
201
- } catch (error) {
202
- logger.error('OpenAI API error', { error: error.message });
203
- throw error;
204
- }
205
- }
206
-
207
- /**
208
- * Count tokens (approximate)
209
- * @param {string} text - Text to count
210
- * @returns {number} - Approximate token count
211
- */
212
- countTokens(text) {
213
- return Math.ceil(text.length / 4);
214
- }
215
-
216
- /**
217
- * Get provider info
218
- * @returns {Object} - Provider information
219
- */
220
- getInfo() {
221
- return {
222
- provider: this.provider,
223
- model: this.model,
224
- hasApiKey: !!this.apiKey
225
- };
226
- }
227
- }
228
-
229
- /**
230
- * Create provider from config
231
- * @param {Object} config - Provider config
232
- * @returns {ModelProvider} - Model provider instance
233
- */
234
- function createProvider(config) {
235
- return new ModelProvider(config);
236
- }
237
-
238
- module.exports = {
239
- ModelProvider,
240
- createProvider
241
- };
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * EZ Model Provider — Unified API for multiple AI providers
5
+ *
6
+ * Supports: Anthropic, Moonshot (Kimi), Alibaba (Qwen), OpenAI
7
+ */
8
+
9
+ const https = require('https');
10
+ const { URL } = require('url');
11
+ const Logger = require('./logger.cjs');
12
+ const logger = new Logger();
13
+
14
+ class ModelProvider {
15
+ /**
16
+ * Create model provider
17
+ * @param {Object} config - Configuration
18
+ */
19
+ constructor(config) {
20
+ this.provider = config.provider || 'anthropic';
21
+ this.model = config.model || 'sonnet';
22
+ this.apiKey = config.apiKey || process.env[`${this.provider.toUpperCase()}_API_KEY`];
23
+
24
+ if (!this.apiKey && this.provider !== 'anthropic') {
25
+ logger.warn('API key not configured', { provider: this.provider });
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Helper for HTTP requests
31
+ */
32
+ _httpRequest(options, data) {
33
+ return new Promise((resolve, reject) => {
34
+ const req = https.request(options, (res) => {
35
+ let body = '';
36
+ res.on('data', (chunk) => body += chunk);
37
+ res.on('end', () => {
38
+ if (res.statusCode >= 200 && res.statusCode < 300) {
39
+ try {
40
+ resolve(JSON.parse(body));
41
+ } catch (e) {
42
+ resolve(body);
43
+ }
44
+ } else {
45
+ reject(new Error(`HTTP ${res.statusCode}: ${body}`));
46
+ }
47
+ });
48
+ });
49
+ req.on('error', reject);
50
+ if (data) req.write(JSON.stringify(data));
51
+ req.end();
52
+ });
53
+ }
54
+
55
+ /**
56
+ * Send chat message
57
+ * @param {Object[]} messages - Chat messages
58
+ * @param {Object} options - Chat options
59
+ * @returns {Promise<Object>} - Response
60
+ */
61
+ async chat(messages, options = {}) {
62
+ logger.info('Chat request', {
63
+ provider: this.provider,
64
+ model: this.model,
65
+ messageCount: messages.length
66
+ });
67
+
68
+ switch (this.provider) {
69
+ case 'anthropic':
70
+ return this._chatAnthropic(messages, options);
71
+ case 'moonshot':
72
+ return this._chatMoonshot(messages, options);
73
+ case 'alibaba':
74
+ case 'qwen':
75
+ return this._chatQwen(messages, options);
76
+ case 'openai':
77
+ return this._chatOpenAI(messages, options);
78
+ default:
79
+ throw new Error(`Unsupported provider: ${this.provider}`);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Anthropic Claude API
85
+ */
86
+ async _chatAnthropic(messages, options) {
87
+ // Anthropic usually requires their SDK or complex headers
88
+ logger.debug('Anthropic chat', { model: this.model });
89
+ return {
90
+ content: '[Anthropic response placeholder - requires SDK]',
91
+ provider: 'anthropic',
92
+ model: this.model
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Moonshot (Kimi) API
98
+ */
99
+ async _chatMoonshot(messages, options) {
100
+ const modelName = this.model === 'sonnet' ? 'moonshot-v1-8k' : this.model;
101
+ const data = {
102
+ model: modelName,
103
+ messages: messages,
104
+ temperature: options.temperature || 0.3
105
+ };
106
+
107
+ const reqOptions = {
108
+ hostname: 'api.moonshot.cn',
109
+ path: '/v1/chat/completions',
110
+ method: 'POST',
111
+ headers: {
112
+ 'Content-Type': 'application/json',
113
+ 'Authorization': `Bearer ${this.apiKey}`
114
+ }
115
+ };
116
+
117
+ try {
118
+ const response = await this._httpRequest(reqOptions, data);
119
+ return {
120
+ content: response.choices[0].message.content,
121
+ provider: 'moonshot',
122
+ model: modelName
123
+ };
124
+ } catch (error) {
125
+ logger.error('Moonshot API error', { error: error.message });
126
+ throw error;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Alibaba Qwen API (DashScope)
132
+ */
133
+ async _chatQwen(messages, options) {
134
+ // Map generic model names to Qwen specific ones
135
+ let modelName = this.model;
136
+ if (modelName === 'sonnet' || modelName === 'gpt-4') modelName = 'qwen-max';
137
+ if (modelName === 'haiku' || modelName === 'gpt-3.5-turbo') modelName = 'qwen-plus';
138
+
139
+ const data = {
140
+ model: modelName,
141
+ input: {
142
+ messages: messages
143
+ },
144
+ parameters: {
145
+ result_format: 'message',
146
+ temperature: options.temperature || 0.3
147
+ }
148
+ };
149
+
150
+ const reqOptions = {
151
+ hostname: 'dashscope.aliyuncs.com',
152
+ path: '/api/v1/services/aigc/text-generation/generation',
153
+ method: 'POST',
154
+ headers: {
155
+ 'Content-Type': 'application/json',
156
+ 'Authorization': `Bearer ${this.apiKey}`
157
+ }
158
+ };
159
+
160
+ try {
161
+ const response = await this._httpRequest(reqOptions, data);
162
+ return {
163
+ content: response.output.choices[0].message.content,
164
+ provider: 'alibaba',
165
+ model: modelName
166
+ };
167
+ } catch (error) {
168
+ logger.error('Qwen API error', { error: error.message });
169
+ throw error;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * OpenAI API
175
+ */
176
+ async _chatOpenAI(messages, options) {
177
+ const modelName = this.model === 'sonnet' ? 'gpt-4-turbo' : this.model;
178
+ const data = {
179
+ model: modelName,
180
+ messages: messages,
181
+ temperature: options.temperature || 0.3
182
+ };
183
+
184
+ const reqOptions = {
185
+ hostname: 'api.openai.com',
186
+ path: '/v1/chat/completions',
187
+ method: 'POST',
188
+ headers: {
189
+ 'Content-Type': 'application/json',
190
+ 'Authorization': `Bearer ${this.apiKey}`
191
+ }
192
+ };
193
+
194
+ try {
195
+ const response = await this._httpRequest(reqOptions, data);
196
+ return {
197
+ content: response.choices[0].message.content,
198
+ provider: 'openai',
199
+ model: modelName
200
+ };
201
+ } catch (error) {
202
+ logger.error('OpenAI API error', { error: error.message });
203
+ throw error;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Count tokens (approximate)
209
+ * @param {string} text - Text to count
210
+ * @returns {number} - Approximate token count
211
+ */
212
+ countTokens(text) {
213
+ return Math.ceil(text.length / 4);
214
+ }
215
+
216
+ /**
217
+ * Get provider info
218
+ * @returns {Object} - Provider information
219
+ */
220
+ getInfo() {
221
+ return {
222
+ provider: this.provider,
223
+ model: this.model,
224
+ hasApiKey: !!this.apiKey
225
+ };
226
+ }
227
+ }
228
+
229
+ /**
230
+ * Create provider from config
231
+ * @param {Object} config - Provider config
232
+ * @returns {ModelProvider} - Model provider instance
233
+ */
234
+ function createProvider(config) {
235
+ return new ModelProvider(config);
236
+ }
237
+
238
+ module.exports = {
239
+ ModelProvider,
240
+ createProvider
241
+ };