@groupchatai/claude-runner 0.1.0 → 0.2.1

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 (2) hide show
  1. package/dist/index.js +48 -20
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -120,13 +120,40 @@ Due: ${new Date(detail.task.dueDate).toLocaleDateString()}`);
120
120
  );
121
121
  return parts.join("\n");
122
122
  }
123
+ var C = {
124
+ reset: "\x1B[0m",
125
+ dim: "\x1B[2m",
126
+ white: "\x1B[97m",
127
+ grey: "\x1B[90m",
128
+ lightGrey: "\x1B[37m",
129
+ green: "\x1B[32m",
130
+ red: "\x1B[31m",
131
+ pid: "\x1B[38;2;193;95;60m"
132
+ };
133
+ function pidTag(pid) {
134
+ return ` ${C.pid}[pid ${pid}]${C.reset}`;
135
+ }
136
+ function padForTag(pid) {
137
+ const tagLen = ` [pid ${pid}] `.length;
138
+ return " ".repeat(tagLen);
139
+ }
140
+ function wrapLines(tag, pad, text, color) {
141
+ const lines = text.split("\n").filter((l) => l.trim());
142
+ if (lines.length === 0) return "";
143
+ const first = `${tag} ${color}${lines[0]}${C.reset}`;
144
+ if (lines.length === 1) return first;
145
+ const rest = lines.slice(1).map((l) => `${pad}${color}${l}${C.reset}`);
146
+ return [first, ...rest].join("\n");
147
+ }
123
148
  function formatStreamEvent(event, pid) {
124
- const prefix = ` [pid ${pid}]`;
149
+ const tag = pidTag(pid);
150
+ const pad = padForTag(pid);
125
151
  switch (event.type) {
126
152
  case "system":
127
153
  if (event.subtype === "init") {
128
- let line = `${prefix} session started`;
154
+ let line = `${tag} ${C.dim}session started`;
129
155
  if (event.session_id) line += ` (${event.session_id})`;
156
+ line += C.reset;
130
157
  return line;
131
158
  }
132
159
  return null;
@@ -136,21 +163,20 @@ function formatStreamEvent(event, pid) {
136
163
  const parts = [];
137
164
  for (const block of blocks) {
138
165
  if (block.type === "text" && block.text) {
139
- for (const line of block.text.split("\n")) {
140
- if (line.trim()) parts.push(`${prefix} \u{1F4AC} ${line}`);
141
- }
166
+ const wrapped = wrapLines(tag, pad, block.text, C.white);
167
+ if (wrapped) parts.push(wrapped);
142
168
  } else if (block.type === "tool_use" && block.name) {
143
169
  let detail = block.name;
144
170
  const input = block.input;
145
171
  if (input) {
146
172
  if (typeof input.file_path === "string") {
147
- detail += ` \u2192 ${input.file_path}`;
173
+ detail += ` ${C.grey}\u2192${C.lightGrey} ${input.file_path}`;
148
174
  } else if (typeof input.command === "string") {
149
175
  const cmd = input.command.length > 80 ? input.command.slice(0, 77) + "\u2026" : input.command;
150
- detail += ` \u2192 ${cmd}`;
176
+ detail += ` ${C.grey}\u2192${C.lightGrey} ${cmd}`;
151
177
  }
152
178
  }
153
- parts.push(`${prefix} \u{1F527} ${detail}`);
179
+ parts.push(`${tag} ${C.grey}${detail}${C.reset}`);
154
180
  }
155
181
  }
156
182
  return parts.length > 0 ? parts.join("\n") : null;
@@ -161,11 +187,11 @@ function formatStreamEvent(event, pid) {
161
187
  const lines = [];
162
188
  if (event.cost_usd !== void 0 || event.total_cost_usd !== void 0) {
163
189
  const cost = event.cost_usd ?? event.total_cost_usd;
164
- lines.push(`${prefix} \u{1F4B0} cost: $${cost?.toFixed(4)}`);
190
+ lines.push(`${tag} ${C.dim}cost: $${cost?.toFixed(4)}${C.reset}`);
165
191
  }
166
192
  if (event.result) {
167
- const preview = event.result.length > 120 ? event.result.slice(0, 117) + "\u2026" : event.result;
168
- lines.push(`${prefix} \u2705 ${preview}`);
193
+ const wrapped = wrapLines(tag, pad, `\u2713 ${event.result}`, C.green);
194
+ if (wrapped) lines.push(wrapped);
169
195
  }
170
196
  return lines.length > 0 ? lines.join("\n") : null;
171
197
  }
@@ -257,7 +283,7 @@ function spawnClaudeCode(prompt, config, runOptions) {
257
283
  const formatted = formatStreamEvent(event, pid);
258
284
  if (formatted) console.log(formatted);
259
285
  } catch {
260
- console.log(` [pid ${pid}] ${trimmed}`);
286
+ console.log(`${pidTag(pid)} ${C.dim}${trimmed}${C.reset}`);
261
287
  }
262
288
  }
263
289
  });
@@ -265,7 +291,7 @@ function spawnClaudeCode(prompt, config, runOptions) {
265
291
  errChunks.push(data);
266
292
  if (config.verbose) {
267
293
  const text = data.toString("utf-8").trimEnd();
268
- if (text) console.error(` [pid ${pid}] ${text}`);
294
+ if (text) console.error(`${pidTag(pid)} ${C.dim}${text}${C.reset}`);
269
295
  }
270
296
  });
271
297
  child.on("error", (err) => reject(new Error(`Failed to spawn claude: ${err.message}`)));
@@ -277,7 +303,7 @@ function spawnClaudeCode(prompt, config, runOptions) {
277
303
  const formatted = formatStreamEvent(event, pid);
278
304
  if (formatted) console.log(formatted);
279
305
  } catch {
280
- console.log(` [pid ${pid}] ${lineBuf.trim()}`);
306
+ console.log(`${pidTag(pid)} ${C.dim}${lineBuf.trim()}${C.reset}`);
281
307
  }
282
308
  }
283
309
  const rawOutput = Buffer.concat(chunks).toString("utf-8");
@@ -349,7 +375,9 @@ function extractPullRequestUrl(stdout) {
349
375
  return void 0;
350
376
  }
351
377
  async function processRun(client, run, config) {
352
- const log = (msg) => console.log(` [${run.id.slice(-8)}] ${msg}`);
378
+ const runTag = ` ${C.pid}[${run.id.slice(-8)}]${C.reset}`;
379
+ const log = (msg) => console.log(`${runTag} ${msg}`);
380
+ const logGreen = (msg) => console.log(`${runTag} ${C.green}${msg}${C.reset}`);
353
381
  const detail = await client.getRunDetail(run.id);
354
382
  const ownerName = run.owner?.name ?? detail.owner?.name ?? "unknown";
355
383
  log(`\u{1F4CB} "${run.taskTitle}" \u2014 delegated by ${ownerName}`);
@@ -402,15 +430,15 @@ async function processRun(client, run, config) {
402
430
  ${stdout.slice(0, 2e3)}
403
431
  \`\`\``;
404
432
  await client.errorRun(run.id, errorMsg, { pullRequestUrl });
405
- log(`\u274C Run errored (exit code ${exitCode})`);
433
+ log(`${C.red}\u274C Run errored (exit code ${exitCode})${C.reset}`);
406
434
  return;
407
435
  }
408
436
  const resultText = extractResultText(stdout);
409
437
  const cost = extractCost(stdout);
410
438
  const summary = resultText;
411
439
  await client.completeRun(run.id, summary, { ...cost, pullRequestUrl });
412
- if (pullRequestUrl) log(`\u{1F517} PR: ${pullRequestUrl}`);
413
- log(`\u2705 Run completed`);
440
+ if (pullRequestUrl) logGreen(`\u{1F517} PR: ${pullRequestUrl}`);
441
+ logGreen(`\u2705 Run completed`);
414
442
  } catch (err) {
415
443
  const message = err instanceof Error ? err.message : String(err);
416
444
  const errorBody = `Claude Code runner error:
@@ -420,9 +448,9 @@ ${message.slice(0, 2e3)}
420
448
  try {
421
449
  await client.errorRun(run.id, errorBody);
422
450
  } catch {
423
- log(`\u26A0 Failed to report error to API`);
451
+ log(`${C.dim}\u26A0 Failed to report error to API${C.reset}`);
424
452
  }
425
- log(`\u274C Error: ${message}`);
453
+ log(`${C.red}\u274C Error: ${message}${C.reset}`);
426
454
  }
427
455
  }
428
456
  function loadEnvFile() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groupchatai/claude-runner",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "Run GroupChat AI agent tasks locally with Claude Code",
5
5
  "type": "module",
6
6
  "bin": {