bunosh 0.4.0 → 0.4.6

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/task.js CHANGED
@@ -185,7 +185,7 @@ export async function task(name, fn, isSilent = false) {
185
185
  printer.finish(name);
186
186
  runningTasks.delete(taskInfo.id);
187
187
 
188
- return result;
188
+ return TaskResult.success(result, { taskType: 'task' });
189
189
  } catch (err) {
190
190
  const endTime = Date.now();
191
191
  const duration = endTime - taskInfo.startTime;
@@ -212,13 +212,14 @@ export async function task(name, fn, isSilent = false) {
212
212
  process.exit(1);
213
213
  }
214
214
 
215
- throw err;
215
+ return TaskResult.fail(err.message, { taskType: 'task', error: err });
216
216
  }
217
217
  }
218
218
 
219
219
  // Add try method to task function
220
220
  task.try = tryTask;
221
221
 
222
+
222
223
  export class SilentTaskWrapper {
223
224
  constructor() {
224
225
  this.silent = true;
@@ -246,9 +247,10 @@ export function silent() {
246
247
  }
247
248
 
248
249
  export class TaskResult {
249
- constructor({ status, output }) {
250
+ constructor({ status, output, metadata = {} }) {
250
251
  this.status = status;
251
252
  this.output = output;
253
+ this._metadata = metadata;
252
254
  }
253
255
 
254
256
  get hasFailed() {
@@ -263,15 +265,76 @@ export class TaskResult {
263
265
  return this.status === TaskStatus.WARNING;
264
266
  }
265
267
 
266
- static fail(output = null) {
267
- return new TaskResult({ status: TaskStatus.FAIL, output });
268
+ async json() {
269
+ const taskType = this._metadata.taskType || 'unknown';
270
+
271
+ switch (taskType) {
272
+ case 'fetch':
273
+ // For fetch tasks, parse the response body as JSON
274
+ if (this._metadata.response) {
275
+ try {
276
+ return await this._metadata.response.json();
277
+ } catch (error) {
278
+ throw new Error(`Failed to parse fetch response as JSON: ${error.message}`);
279
+ }
280
+ } else if (typeof this.output === 'string') {
281
+ try {
282
+ return JSON.parse(this.output);
283
+ } catch (error) {
284
+ throw new Error(`Failed to parse fetch output as JSON: ${error.message}`);
285
+ }
286
+ }
287
+ throw new Error('No JSON data available from fetch task');
288
+
289
+ case 'exec':
290
+ case 'shell':
291
+ // For exec/shell tasks, return structured output
292
+ const lines = this.output ? this.output.split('\n').filter(line => line.trim()) : [];
293
+ return {
294
+ stdout: this._metadata.stdout || this.output || '',
295
+ stderr: this._metadata.stderr || '',
296
+ exitCode: this._metadata.exitCode || (this.hasFailed ? 1 : 0),
297
+ lines
298
+ };
299
+
300
+ case 'ai':
301
+ // For AI tasks, return the structured output if available
302
+ if (typeof this.output === 'object') {
303
+ return this.output;
304
+ } else if (typeof this.output === 'string') {
305
+ try {
306
+ return JSON.parse(this.output);
307
+ } catch (error) {
308
+ // If it's not JSON, return as text property
309
+ return { text: this.output };
310
+ }
311
+ }
312
+ return { text: this.output || '' };
313
+
314
+ default:
315
+ // For unknown task types, try to parse output as JSON or return as text
316
+ if (typeof this.output === 'object') {
317
+ return this.output;
318
+ } else if (typeof this.output === 'string') {
319
+ try {
320
+ return JSON.parse(this.output);
321
+ } catch (error) {
322
+ return { text: this.output };
323
+ }
324
+ }
325
+ return { text: this.output || '' };
326
+ }
327
+ }
328
+
329
+ static fail(output = null, metadata = {}) {
330
+ return new TaskResult({ status: TaskStatus.FAIL, output, metadata });
268
331
  }
269
332
 
270
- static success(output = null) {
271
- return new TaskResult({ status: TaskStatus.SUCCESS, output });
333
+ static success(output = null, metadata = {}) {
334
+ return new TaskResult({ status: TaskStatus.SUCCESS, output, metadata });
272
335
  }
273
336
 
274
- static warning(output = null) {
275
- return new TaskResult({ status: TaskStatus.WARNING, output });
337
+ static warning(output = null, metadata = {}) {
338
+ return new TaskResult({ status: TaskStatus.WARNING, output, metadata });
276
339
  }
277
340
  }
package/src/tasks/ai.js CHANGED
@@ -118,15 +118,23 @@ async function ai(prompt, outputFormat = null) {
118
118
  process.stdout.write('\r' + ' '.repeat(20) + '\r');
119
119
  const tokenInfo = usage ? `${usage.totalTokens} tokens` : '';
120
120
  printer.finish(taskName, { tokenInfo });
121
+
122
+ const metadata = {
123
+ taskType: 'ai',
124
+ outputFormat: !!outputFormat,
125
+ usage,
126
+ prompt: cleanPrompt
127
+ };
128
+
121
129
  finishTaskInfo(taskInfo, true, null, outputFormat ? JSON.stringify(result, null, 2) : result);
122
- return TaskResult.success(result);
130
+ return TaskResult.success(result, metadata);
123
131
 
124
132
  } catch (error) {
125
133
  clearInterval(progressInterval);
126
134
  process.stdout.write('\r' + ' '.repeat(20) + '\r');
127
135
  printer.error(taskName, error);
128
136
  finishTaskInfo(taskInfo, false, error, error.message);
129
- return TaskResult.fail(error.message);
137
+ return TaskResult.fail(error.message, { taskType: 'ai' });
130
138
  }
131
139
  }
132
140
 
package/src/tasks/exec.js CHANGED
@@ -62,6 +62,8 @@ export default function exec(strings, ...values) {
62
62
 
63
63
  const decoder = new TextDecoder();
64
64
  let output = '';
65
+ let stdout = '';
66
+ let stderr = '';
65
67
  let finished = false;
66
68
 
67
69
  // Process stdout
@@ -84,6 +86,7 @@ export default function exec(strings, ...values) {
84
86
  if (line.trim()) {
85
87
  printer.output(line);
86
88
  output += line + '\n';
89
+ stdout += line + '\n';
87
90
  }
88
91
  }
89
92
  }
@@ -91,6 +94,7 @@ export default function exec(strings, ...values) {
91
94
  if (buffer.trim()) {
92
95
  printer.output(buffer);
93
96
  output += buffer + '\n';
97
+ stdout += buffer + '\n';
94
98
  }
95
99
  } finally {
96
100
  reader.releaseLock();
@@ -117,6 +121,7 @@ export default function exec(strings, ...values) {
117
121
  if (line.trim()) {
118
122
  printer.output(line, true);
119
123
  output += line + '\n';
124
+ stderr += line + '\n';
120
125
  }
121
126
  }
122
127
  }
@@ -124,6 +129,7 @@ export default function exec(strings, ...values) {
124
129
  if (buffer.trim()) {
125
130
  printer.output(buffer, true);
126
131
  output += buffer + '\n';
132
+ stderr += buffer + '\n';
127
133
  }
128
134
  } finally {
129
135
  reader.releaseLock();
@@ -140,20 +146,27 @@ export default function exec(strings, ...values) {
140
146
  finished = true;
141
147
  const exitCode = parseInt(exitResult, 10);
142
148
 
149
+ const metadata = {
150
+ taskType: 'exec',
151
+ exitCode,
152
+ stdout: stdout.trim(),
153
+ stderr: stderr.trim()
154
+ };
155
+
143
156
  if (exitCode === 0) {
144
157
  printer.finish(cmd);
145
158
  finishTaskInfo(taskInfo, true, null, output.trim());
146
- resolve(TaskResult.success(output.trim()));
159
+ resolve(TaskResult.success(output.trim(), metadata));
147
160
  } else {
148
161
  const error = new Error(`Exit code: ${exitCode}`);
149
162
  printer.error(cmd, null, { exitCode });
150
163
  finishTaskInfo(taskInfo, false, error, output.trim());
151
- resolve(TaskResult.fail(output.trim()));
164
+ resolve(TaskResult.fail(output.trim(), metadata));
152
165
  }
153
166
  } catch (error) {
154
167
  printer.error(cmd, error);
155
168
  finishTaskInfo(taskInfo, false, error, error.message);
156
- resolve(TaskResult.fail(error.message));
169
+ resolve(TaskResult.fail(error.message, { taskType: 'exec' }));
157
170
  }
158
171
  });
159
172
 
@@ -182,35 +195,44 @@ async function nodeExec(cmd, extraInfo, printer, taskInfo) {
182
195
  });
183
196
 
184
197
  let output = '';
185
- let errorOutput = '';
198
+ let stdout = '';
199
+ let stderr = '';
186
200
 
187
201
  proc.stdout.on('data', (data) => {
188
202
  const text = data.toString();
189
203
  printer.output(text.trim());
190
204
  output += text;
205
+ stdout += text;
191
206
  });
192
207
 
193
208
  proc.stderr.on('data', (data) => {
194
209
  const text = data.toString();
195
210
  printer.output(text.trim(), true);
196
- errorOutput += text;
211
+ output += text;
212
+ stderr += text;
197
213
  });
198
214
 
199
215
  proc.on('close', (code) => {
200
- const combinedOutput = (output + errorOutput).trim();
216
+ const combinedOutput = (output).trim();
217
+ const metadata = {
218
+ taskType: 'exec',
219
+ exitCode: code,
220
+ stdout: stdout.trim(),
221
+ stderr: stderr.trim()
222
+ };
201
223
 
202
224
  if (code === 0) {
203
225
  printer.finish(cmd);
204
- resolve(TaskResult.success(combinedOutput));
226
+ resolve(TaskResult.success(combinedOutput, metadata));
205
227
  } else {
206
228
  printer.error(cmd, new Error(`Exit code: ${code}`));
207
- resolve(TaskResult.fail(combinedOutput));
229
+ resolve(TaskResult.fail(combinedOutput, metadata));
208
230
  }
209
231
  });
210
232
 
211
233
  proc.on('error', (error) => {
212
234
  printer.error(cmd, error);
213
- resolve(TaskResult.fail(error.message));
235
+ resolve(TaskResult.fail(error.message, { taskType: 'exec' }));
214
236
  });
215
237
  });
216
238
  }
@@ -28,21 +28,29 @@ export default async function httpFetch() {
28
28
  }
29
29
  }
30
30
 
31
+ const metadata = {
32
+ taskType: 'fetch',
33
+ response: response.clone(), // Clone to allow json() to be called later
34
+ status: response.status,
35
+ statusText: response.statusText,
36
+ headers: Object.fromEntries(response.headers.entries())
37
+ };
38
+
31
39
  if (response.ok) {
32
40
  printer.finish(taskName, { status: `${response.status} ${response.statusText}` });
33
41
  finishTaskInfo(taskInfo, true, null, output.trim());
34
- return TaskResult.success(output.trim());
42
+ return TaskResult.success(output.trim(), metadata);
35
43
  } else {
36
44
  const errorMsg = `HTTP ${response.status} ${response.statusText}`;
37
45
  const error = new Error(errorMsg);
38
46
  printer.error(taskName, errorMsg);
39
47
  finishTaskInfo(taskInfo, false, error, errorMsg);
40
- return TaskResult.fail(errorMsg);
48
+ return TaskResult.fail(errorMsg, metadata);
41
49
  }
42
50
 
43
51
  } catch (error) {
44
52
  printer.error(taskName, error);
45
53
  finishTaskInfo(taskInfo, false, error, error.message);
46
- return TaskResult.fail(error.message);
54
+ return TaskResult.fail(error.message, { taskType: 'fetch' });
47
55
  }
48
56
  }
@@ -81,9 +81,16 @@ export default function shell(strings, ...values) {
81
81
 
82
82
  const output = await result.text();
83
83
 
84
+ const metadata = {
85
+ taskType: 'shell',
86
+ exitCode: 0,
87
+ stdout: output.trim(),
88
+ stderr: ''
89
+ };
90
+
84
91
  printer.finish(cmd);
85
92
  finishTaskInfo(taskInfo, true, null, output.trim());
86
- resolve(TaskResult.success(output.trim()));
93
+ resolve(TaskResult.success(output.trim(), metadata));
87
94
  return;
88
95
 
89
96
  } catch (shellError) {
@@ -118,22 +125,29 @@ export default function shell(strings, ...values) {
118
125
  }
119
126
  }
120
127
 
128
+ const metadata = {
129
+ taskType: 'shell',
130
+ exitCode: shellError.exitCode,
131
+ stdout: stdout.trim(),
132
+ stderr: stderr.trim()
133
+ };
134
+
121
135
  const error = new Error(`Exit code: ${shellError.exitCode}`);
122
136
  printer.error(cmd, null, { exitCode: shellError.exitCode });
123
137
  finishTaskInfo(taskInfo, false, error, errorOutput);
124
- resolve(TaskResult.fail(errorOutput));
138
+ resolve(TaskResult.fail(errorOutput, metadata));
125
139
  return;
126
140
  } else {
127
141
  const errorMessage = shellError.message || shellError.toString();
128
142
  printer.error(cmd, shellError);
129
143
  finishTaskInfo(taskInfo, false, shellError, errorMessage);
130
- resolve(TaskResult.fail(errorMessage));
144
+ resolve(TaskResult.fail(errorMessage, { taskType: 'shell' }));
131
145
  }
132
146
  }
133
147
  } catch (error) {
134
148
  printer.error(cmd, error);
135
149
  finishTaskInfo(taskInfo, false, error, error.message);
136
- resolve(TaskResult.fail(error.message));
150
+ resolve(TaskResult.fail(error.message, { taskType: 'shell' }));
137
151
  }
138
152
  });
139
153